“泄漏”是什么意思?进入全球范围?

发布于 2024-11-06 22:33:25 字数 2703 浏览 0 评论 0原文

不久前,我提供了一个 JavaScript 设计模式(模块模式 - 见下文),这是我从 John Resig 示例中获得的 某人问题的解决方案的一部分,我收到了以下评论:

“……这个模式有点结束了 设计的但不是那么好。仍然 泄漏到全球范围。和你的 不向异步加载器开放。 但这比临时的要好 编码!”

所以...

如果“泄漏”到全局范围意味着“您的对象被附加到浏览器窗口(对象)”...那么所有内容都已经被附加(全局):

这个“泄漏”进入全局范围:

window.jQuery

…只需调用:window.jQuery 即可解析为 function();

这个“泄漏”到全局范围:

function HelloWorld() { alert(‘Howdy’); }

...只需调用:window.HelloWorld(),您就会得到“Howdy”。

此“泄漏”到全局范围:

var myVariable = 10;

...只需调用:window.myVariable,您将得到 10

如果评论者是正确的,则上述所有内容都“泄漏”进入全球范围。因此,就我个人而言,我认为没有办法不“泄漏”到全局范围,因为即使您的表单控件也存在于其中(也)。

因此,这是我的问题......

  • “泄漏”是什么意思 全球范围?
  • 为什么这么糟糕?
  • 你如何避免它?
  • 当想要创建持久化的时候 自定义对象,为什么是Module 图案(下)不好?
  • 设计模式让你封装 复杂的逻辑,是封装 突然变坏只是因为我们 用 JavaScript 编写
  • 或者……这个评论者根本就是错的吗?

这是我上面提到的模块模式:

<script type="text/javascript">
    var myNamespace = (function($) {
        var publicInstances = {};

        // ***********************
        // myObject
        publicInstances.myObject = myObject;
        function myObject() {

            /// <summary>A pointer to this</summary>
            var self = this;

            this.someProperty = new String();

            this.initialize = function() {
                /// your code here
            }
            this.someMethod = function() {
                /// your code here
            }

            self.initialize();
        }

        return publicInstances;
    })(jQuery);


    jQuery(document).ready(function() {
        // Use would look like
        var myInstance = new myNamespace.myObject();
    });
</script>


UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.

回顾以下答案:
当局部作用域中使用的某些东西无意中可供全局作用域使用时(例如,窗口对象),就会发生“泄漏”到全局作用域中。这很糟糕,因为它会打开页面,导致潜在的命名冲突,从而可能导致变量解析为意外的值或类型。

故意将变量设置为全局变量不被视为“泄漏”。然而,需要正确地为对象命名空间,以减少所述命名冲突的可能性。

您无法避免全局范围的变量,但您可以通过使用 RequireJSCurl

A while ago, I offered-up a JavaScript design pattern (the Module Pattern - see below) that I got from a John Resig example as part of a solution to someone’s question and I received the following comment:

“…that pattern is a bit over
engineered and not that good. Still
leaking into global-scope. and your
not opening yourself to async loaders.
But it is better then just ad-hoc
coding !”

So…

If “leaking” into global scope means “your object gets appended to the browsers window (object)”…then everything already gets appended (globally):

This “leaks” into global scope:

window.jQuery

…just call: window.jQuery and it resolves as a function();

This “leaks” into global scope:

function HelloWorld() { alert(‘Howdy’); }

…just call: window.HelloWorld() and you will get ‘Howdy’.

This “leaks” into global scope:

var myVariable = 10;

…just call: window.myVariable and you will get 10

If the commenter is correct, then all the above “leak” into global-scope. So, personally, I don’t see a way NOT to “leak” into global-scope as even your form controls exists there (as well).

As such, here are my questions…

  • What is meant by “leaking” into
    global-scope?
  • Why is that bad?
  • How do you avoid it?
  • When wanting to create persistent
    custom-objects, why is the Module
    Pattern (below) bad?
  • Design patterns let you encapsulate
    complex logic, is encapsulation
    suddenly bad simply because we’re
    writing in JavaScript
    ?
  • Or...is this commenter simply wrong?

Here is the Module Pattern I Mentioned Above:

<script type="text/javascript">
    var myNamespace = (function($) {
        var publicInstances = {};

        // ***********************
        // myObject
        publicInstances.myObject = myObject;
        function myObject() {

            /// <summary>A pointer to this</summary>
            var self = this;

            this.someProperty = new String();

            this.initialize = function() {
                /// your code here
            }
            this.someMethod = function() {
                /// your code here
            }

            self.initialize();
        }

        return publicInstances;
    })(jQuery);


    jQuery(document).ready(function() {
        // Use would look like
        var myInstance = new myNamespace.myObject();
    });
</script>


UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.

TO RECAP THE ANSWERS BELOW:
"Leaking" into global-scope occurs when something used in local-scope is unintentionally made available to the global-scope (e.g. the window object). This is bad because it opens the page to potential naming collisions which could result in variables resolving to unexpected values or types.

Intentionally making a variable global is not considered a "leak". However, properly namespacing the object is required to reduce potential for said naming collisions.

You cannot avoid globally-scoped variables, but you can reduce the above risks by using asynchronous-loaders and defining-modules made available in plug-ins like RequireJS or Curl.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

套路撩心 2024-11-13 22:33:25

“泄漏”到全局范围是指本地范围中使用的某些内容无意中可供全局范围使用。这意味着分配给当前范围内尚未定义的变量:

function myFunction() {
    a=1;
}

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

这很糟糕,因为可能存在命名冲突,导致变量具有与预期不同的值/类型。当您忘记对 for 语句中使用的变量使用 var 关键字时,还可能导致旧版 Internet Explorer 中出现错误。

我不会将故意将变量设置为全局变量归类为“泄漏”,因为这更像是您将其“倒入”全局范围。然而,这仍然经常被一些人认为是不好的做法(尽管我认为这有点夸张),因为与 window 对象的当前属性或其他脚本和库设置的变量仍然存在潜在的命名冲突。

"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.

油焖大侠 2024-11-13 22:33:25

[[短篇故事]]

不要创建全局变量并使用异步模块加载器,例如 requirejs 或 curl

[[长篇故事]]

该评论的结构很差。

模块系统没有任何问题。我根本就抱怨使用全局变量。 (我仍然认为完整的通用模块模式是臃肿的)。

是否应该避免所有全局变量是一个不同的问题,我认为这是风格问题。您可以使用异步加载器来传递模块,也可以使用 window 来传递模块。

  • “泄漏”到全球范围是什么意思?

我的意思是你创建全局变量。最小化全局变量的使用是一种模式。在函数式编程中,全局变量可以为零,但这与使用全局模块是不同的模式。

  • 为什么这么糟糕?

全局存在任何状态都可能导致该状态被破坏。

  • 你如何避免它?

你不能。不过,您可以最大限度地减少全局变量的数量。为了完全避免全局状态,您可以使用异步加载器。它们为您定义了一些随后可以使用的全局变量。

  • 当想要创建持久的自定义对象时,为什么模块模式(如下)不好?

模块模式没有任何问题。问题是全局存储您的模块。问题在于全局命名空间。

  • 设计模式可以让你封装复杂的逻辑,仅仅因为我们用 JavaScript 编写,封装就突然变得很糟糕吗?

现在我已经弄清楚了评论的意图,这个问题并不真正相关

  • ,或者......这个评论者根本就是错误的吗?

该评论充其量是措辞不佳。我反对全局名称空间而不是模块,但没有正确说明这一点。

另一种方法是使用异步加载器并定义模块。这些可以缩小到两个全局变量。 定义require

require = function(moduleName,callback)

这将获取一个模块,然后将其返回给您。

define = function(obj)

这定义了一个模块。

这里的概念是多文件代码如下:

// 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):
})();

[[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):
})();
-残月青衣踏尘吟 2024-11-13 22:33:25

您的模块仅“泄漏”它的名称空间持有者,因此这是相当可以接受的。

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

始终不够 2024-11-13 22:33:25

使用 RequireJS 的加载器示例:

在 utils.js 中定义实用程序模块:

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

在另一个模块(例如 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;
        }
    };
});

您可以在另一个文件中使用 math.js,例如 main.js:

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

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

您仍然可以拥有命名空间,并仍然让它们在模块内保持温暖和舒适:

namespace.js:

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

然后其余模块可以在定义期间使用此命名空间:

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

或者在运行时,在其他一些模块中:

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

在用法中上面,除了 definerequire 之外,没有其他内容是全局的。当然,这些只是说明性示例,因为在 RequireJS 中定义/使用模块有许多不同的风格。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文