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.


Reply via email to