What is meant by “leaking” into global scope?

寵の児 提交于 2019-11-28 07:33:58
Raynos

[[Short story]]

Don't make global variables ever and use an async module loader like requirejs or curl

[[Long story]]

That comment was poorly structured.

There is nothing wrong with the module system. I was complaining about using global variables at all. (I still think the full generic module pattern is bloated).

Whether you should avoid all global variables is a different question and I think a matter of style. You can either use an async loader to pass modules around or using window to pass modules around.

  • What is meant by “leaking” into global-scope?

What I meant was your creating global variables. Minimising the use of global variables is a pattern. In functional style programming it's possible to have zero global variables but this is a different pattern from using global modules.

  • Why is that bad?

Having any state globally can cause that state to be corrupted.

  • How do you avoid it?

You can't. You can minimize the amount of global variables though. To avoid having global state completely you can use asynchronous loaders. These define a few global variables for you that you can then use.

  • When wanting to create persistent custom-objects, why is the Module Pattern (below) bad?

There is nothing wrong with the module pattern. The problem is storing your module globally. The issue is having global namespaces.

  • Design patterns let you encapsulate complex logic, is encapsulation suddenly bad simply because we’re writing in JavaScript?

Now that I've cleared up the intent of the comment this question isn't really relevant

  • Or...is this commenter simply wrong?

The comment was poorly phrased at best. I objected to global namespaces rather than modules, but did not state this properly.

The alternative is using asynchronous loaders and defining modules. These can be narrowed down to two global variables. define and require.

require = function(moduleName, callback)

This will get a module and then return it to you.

define = function(obj)

this defines a module.

The concept here is that you multi file code as follows:

// main.js
require([
  "foo.js",
  "bar.js",
  ...,
], function(foo, bar, ...) {
   // do stuff
}); 

//foo.js

(function() {
    var namespace = modulePatternCode;
    ...
    define(namespace):
})();

//bar.js 

(function() {
    var namespace = modulePatternCode;
    ...
    define(namespace):
})();

"Leaking" into global scope is when something used in a local scope is unintentionally made available to the global scope. That means assigning to a variable not already defined in the current scope:

function myFunction() {
    a=1;
}

myFunction();
alert(a);
//-> 1

It's bad because there could be naming collisions resulting in variables with different values/types than expected. It can also lead to a bug in older Internet Explorers when you forget to use the var keyword for a variable used in a for statement.

I wouldn't class intentionally making a variable global as "leaking", because it's more like you're "pouring" it into the global scope. However, this is still often considered bad practice by some (although I think that's a little melodramatic) because there are still potential naming collisions with current properties of the window object, or variables set by other scripts and libraries.

Your module only "leaks" it's namespace holder so it's pretty acceptable.

Ates Goral

Loader example using RequireJS:

Define a utilities module in utils.js:

define(function () {
    return {
        each: function (iterable, callback) {
            // ...
        },
        map: function (iterable, mapper) {
            // ...
        }
    };
});

Use the above module in another module, say math.js:

define([ "utils" ], function (utils) {
    return {
        sum: function (numbers) {
            var sum = 0;

            utils.each(numbers, function (n) {
                sum += n;
            });

            return sum;
        },
        average: function (numbers) {
            return this.sum(numbers) / numbers.length;
        }
    };
});

And you can use math.js in another file, say main.js:

console.log("About to add 1-3");

require([ "math" ], function (math) {
    console.log(math.sum([ 1, 2, 3 ]));
});

You can still have namespaces, and still keep them warm and cozy inside modules:

namespace.js:

define([ "foo", "bar", "moo" ] function (foo, bar, moo) {
    return {
        foo: foo,
        bar: bar,
        moo: moo
    };
});

Then the rest of the modules can use this namespace during definition:

define([ "namespace" ], function (namespace) {
    namespace.foo(42);
});

Or at runtime, in some other module:

define(function () {
    return {
        initialize: function () {
            require([ "namespace" ], function (namespace) {
                namespace.foo(42);
            });
        }
    };
});

In the usages above, nothing but define and require are global. Of course, these are just illustrative examples, as there are many different flavors of defining/using modules in RequireJS.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!