什么是"泄漏"到全球范围?

Pri*_*ERO 17 javascript jquery design-patterns globals

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

"......这种模式有点过于设计而不是那么好.仍然渗透到全球范围.而你不打开自己的异步装载机.但它比ad-hoc编码更好!"

所以…

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

这"泄漏"到全球范围:

window.jQuery
Run Code Online (Sandbox Code Playgroud)

...只需调用: window.jQuery并将其解析为函数();

这"泄漏"到全球范围:

function HelloWorld() { alert(‘Howdy’); }
Run Code Online (Sandbox Code Playgroud)

......打电话给window.HelloWorld()你:你会得到'你好'.

这"泄漏"到全球范围:

var myVariable = 10;
Run Code Online (Sandbox Code Playgroud)

......打电话给window.myVariable你:你会得到10分

如果评论者是正确的,那么以上所有"泄漏"到全球范围.所以,就个人而言,我没有看到一种不"泄漏"到全局范围内的方法,因为即使你的表单控件也存在(也是如此).

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

  • 什么是"泄漏"到全球范围?
  • 为什么那么糟糕?
  • 你怎么避免它?
  • 当想要创建持久的自定义对象时,为什么模块模式(下面)不好?
  • 设计模式让你封装复杂的逻辑,封装突然变坏只是因为我们用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>
Run Code Online (Sandbox Code Playgroud)


更新:
我对以下答案感到满意,并感谢大家花时间发表评论.

重新获得以下答案:
当局部范围内使用的东西无意中可用于全局范围(例如窗口对象)时,会发生"泄漏"到全局范围.这很糟糕,因为它会打开页面以查找可能导致变量解析为意外值或类型的潜在命名冲突.

故意使变量全局化不被视为"泄漏".但是,需要正确地命名对象以减少所述命名冲突的可能性.

您无法避免全局范围的变量,但您可以通过使用异步加载器和在RequireJSCurl等插件中提供的定义模块来降低上述风险.

And*_*y E 6

"泄漏"到全球范围内是指本地范围内使用的内容无意中可用于全球范围.这意味着分配给当前范围中尚未定义的变量:

function myFunction() {
    a=1;
}

myFunction();
alert(a);
//-> 1
Run Code Online (Sandbox Code Playgroud)

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

我不打算故意将变量全局变为"泄漏",因为它更像是将它"倾注"到全球范围内.然而,这仍然被一些人认为是不好的做法(尽管我认为这有点戏剧性),因为仍然存在与window对象的当前属性或其他脚本和库设置的变量的潜在命名冲突.


Ray*_*nos 5

[[短篇故事]]

永远不要创建全局变量并使用像requirejscurl这样的异步模块加载器

[[很长的故事]]

该评论结构不佳。

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

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

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

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

  • 为什么那么糟糕?

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

  • 你如何避免它?

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

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

模块模式没有任何问题。问题是全局存储模块。问题是具有全局命名空间。

  • 设计模式让你封装复杂的逻辑,封装突然就糟糕了,因为我们是用 JavaScript 编写的吗?

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

  • 或者……这个评论者只是错了吗?

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

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

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):
})();
Run Code Online (Sandbox Code Playgroud)

  • @AndyE 哎呀!那是意味着。@PrisonerZERO [requirejs](http://requirejs.org/) 具有我提到的确切(或多或少)语法。它还有一整套支持工具,可以将其用作异步加载器。 (2认同)