On 11/12/13 14:22, Attila Szegedi wrote:
On Dec 11, 2013, at 3:08 PM, Tim Fox <[email protected]> wrote:

On 11/12/13 13:50, Attila Szegedi wrote:
On Dec 11, 2013, at 2:22 PM, Tim Fox <[email protected]> wrote:

On 11/12/13 13:19, A. Sundararajan wrote:
The way Avatar/js project ( https://java.net/projects/avatar-js ) project 
implements CommonJS/require is as follows.

It creates a anonymous function code wrapping a module (say like http.js). The 
anonymous function accepts 'exports' as argument. When you eval that code at 
top level global scope, because of the anon function wrapping around, all top 
level vars in a module code like http.js become locals of that anon function.
Isn't that the same as what I described in my last post?

If so, the problem with that is that globals that aren't prefixed with var 
still leak.
I might be mistaken, but isn't that the best technique browser-based (pure 
JavaScript) require() implementations can do too? Again, not justifying the 
design (I'm saying this a lot today), just pointing out that a widespread 
deployment base - namely, all browsers - might also suffer from the problem.
tbh I don't think CommonJS is used much in browsers, but most probably any 
browser implementation would have the same issue with non var globals leaking 
too.

Having said that it should be possible to get around the leaking non var global 
issue even using a pure JS require.

If you pre-parsed the JavaScript before executing it (would need a JS parser 
written in JS for this, e.g. JSLint), you could, I guess prefix any non var 
globals with a namespace, e.g.

myglobal = 123;

function foo() {
   return myglobal;
}

would be transformed to:

somenamespace.myglobal = 123;

function foo() {
  return somenamespace.myglobal
}

Where somenamespace could be generated using a random UUID or such-like.

You can also prevent modules that assign to new globals from loading by forcing 
a strict eval:

function loadModule(src) {
     "use strict";

     var _exports = {};
     eval("(function(exports){" + src + "})(_exports)");
     return _exports;
}

With this function

        loadModule("x = 1")

will throw a ReferenceError.

        var m = loadModule("var x = 2; exports.f = function() { return x }")

on the other hand will work, and m.f() will print 2.

Of course, this doesn't prevent the module script from modifying an _existing_ 
global, but this is as far as we can get.

Attila.

Thanks for the tip :)



Reply via email to