Javascript 使用 (function(window, document, undefined) { ... })(window, document) 有什么好处?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5020479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:16:22  来源:igfitidea点击:

What advantages does using (function(window, document, undefined) { ... })(window, document) confer?

javascript

提问by Gregory Bell

I guess using this pattern is the new hotness, but I don't understand what the advantage is and I don't understand the scoping implications.

我想使用这种模式是新的热点,但我不明白优势是什么,我不明白范围界定的含义。

The pattern:

图案:

(function(window, document, undefined){
  window.MyObject = {
    methodA: function() { ... },
    methodB: function() { ... }
  };
})(window, document)

So I have several questions about this.

所以我有几个问题。

Is there a particular advantage to encapsulating an object like this?
Why are windowand documentbeing fed in instead of just being accessed normally?
Why the heck is undefinedbeing passed in?
Is attaching the object we're creating directly to window a particularly good idea?

封装这样的对象有什么特别的好处吗?
为什么窗口文档被送入而不是正常访问?
为什么undefined要传入?
将我们正在创建的对象直接附加到窗口是一个特别好的主意吗?

I'm used to what I'll call the Crockford style of Javascript encapsulation (because I got it off the Douglas Crockford Javascript videos).

我已经习惯了我称之为 Crockford 风格的 Javascript 封装(因为我从 Douglas Crockford Javascript 视频中得到了它)。

NameSpace.MyObject = function() {
  // Private methods
  // These methods are available in the closure
  // but are not exposed outside the object we'll be returning.
  var methodA = function() { ... };

  // Public methods
  // We return an object that uses our private functions,
  // but only exposes the interface we want to be available.
  return {

    methodB: function() {
      var a = methodA();
    },
    methodC: function() { ... }

  }
// Note that we're executing the function here.
}();

Is one of these patterns functionally better than the other? Is the first one an evolution of the other?

这些模式中的一个在功能上比另一个更好吗?第一个是另一个的进化吗?

采纳答案by CMS

Why are window and document being fed in instead of just being accessed normally?

为什么窗口和文档被送入而不是正常访问?

Generally to fasten the identifier resolution process, having them as local variables can help (although IMO the performance improvements may be negligible).

通常为了加快标识符解析过程,将它们作为局部变量会有所帮助(尽管 IMO 性能改进可能可以忽略不计)。

Passing the global object is also a widely used technique on non-browser environments, where you don't have a windowidentifier at the global scope, e.g.:

在非浏览器环境中传递全局对象也是一种广泛使用的技术,在这种环境中,您window在全局范围内没有标识符,例如:

(function (global) {
  //..
})(this); // this on the global execution context is 
          // the global object itself

Why the heck is undefined being passed in?

为什么 undefined 被传入?

This is made because the undefinedglobal property in ECMAScript 3, is mutable, meaning that someone could change its value affecting your code, for example:

这是因为undefinedECMAScript 3 中的全局属性是可变的,这意味着有人可以更改其值影响您的代码,例如:

undefined = true; // mutable
(function (undefined) {
  alert(typeof undefined); // "undefined", the local identifier
})(); // <-- no value passed, undefined by default

If you look carefully undefinedis actually not being passed (there's no argument on the function call), that's one of the reliable ways to get the undefinedvalue, without using the property window.undefined.

如果仔细查看undefined实际上是没有被传递(函数调用没有参数),这是获取undefined值的可靠方法之一,而不使用属性window.undefined

The name undefinedin JavaScript doesn't mean anything special, is not a keyword like true, false, etc..., it's just an identifier.

这个名字undefined在JavaScript并不代表什么特别的,是不是像一个关键字truefalse等等...,它只是一个标识符。

Just for the record, in ECMAScript 5, this property was made non-writable...

只是为了记录,在 ECMAScript 5 中,这个属性被设置为不可写......

Is attaching the object we're creating directly to window a particularly good idea?

将我们正在创建的对象直接附加到窗口是一个特别好的主意吗?

It's a common way used to declare global properties when you are on another function scope.

当您处于另一个函数作用域时,这是用于声明全局属性的常用方法。

回答by josh3736

This particular style does bring some benefits over the "Crockford" style. Primarily, passing windowand documentallows the script to be more efficiently minified. A minifier can rename those parameters to single-character names, saving 5 and 7 bytes respectively per reference. This can add up: jQuery references window33 times and document91 times. Minifying each token down to one character saves 802 bytes.

这种特殊的风格确实比“Crockford”风格带来了一些好处。首先,传递windowdocument允许更有效地缩小脚本。压缩器可以将这些参数重命名为单字符名称,每个引用分别节省 5 和 7 个字节。这可以加起来:jQuery 引用了window33 次和document91 次。将每个标记缩小为一个字符可节省 802 个字节。

Additionally, you doget an execution speed benefit. When I first read @joekarl's assertion that it provides a performance benefit, I thought, "that seems rather spurious." So I profiled the actual performance with a test page. Referencing windowone hundred milliontimes, the local variable reference provides a modest 20% speed increase (4200 ms to 3400ms) in Firefox 3.6 and a shocking 31,000% increase (13 sec to 400ms) in Chrome 9.

此外,您确实获得了执行速度的好处。当我第一次阅读@joekarl声称它提供了性能优势的断言时,我想,“这似乎相当虚假。” 所以我用一个测试页描述了实际性能。引用window一亿次,本地变量引用在 Firefox 3.6 中提供了 20% 的适度速度提升(4200 毫秒到 3400 毫秒),在 Chrome 9 中提供了惊人的 31,000% 增加(13 秒到 400 毫秒)。

Of course, you're never going to reference window100,000,000 times in practice, and even 10,000 direct references only take 1ms in Chrome, so the actual performance gain here is almost completely negligible.

当然,window在实践中你永远不会引用100,000,000 次,甚至 10,000 次直接引用在 Chrome 中也只需要 1ms,所以这里的实际性能提升几乎完全可以忽略不计。

Why the heck is undefinedbeing passed in?

为什么undefined要传入?

Because (as mentioned by @CMS) the token undefinedis actually undefined. Unlike null, it has no special meaning, and you're free to assign to this identifier like any other variable name. (Note, however, that this is no longer true in ECMAScript 5.)

因为(正如@CMS所提到的)令牌undefined实际上是 undefined。与 不同null,它没有特殊含义,您可以像任何其他变量名一样自由地分配给这个标识符。(但是请注意,这在 ECMAScript 5 中不再成立。)

Is attaching the object we're creating directly to window a particularly good idea?

将我们正在创建的对象直接附加到窗口是一个特别好的主意吗?

The windowobject is the global scope, so that's exactly what you're doing at some point, whether or not you explictly write "window." window.Namespace = {};and Namespace = {};are equivalent.

window对象是全局作用域,所以这正是您在某个时候所做的,无论您是否明确地编写了“window”。 window.Namespace = {};并且Namespace = {};是等价的。

回答by joekarl

I'm with you in using Crockford's style.

我和你一起使用克罗克福德的风格。

To answer your questions

回答您的问题

1.Is there a particular advantage to encapsulating an object like this?

1.像这样封装一个对象有什么特别的好处吗?

The only advantage I can see is by making window and document local variables instead of global variables, you get some added safety by not being able to directly overwrite either one and also some performance gain by them both being local.

我能看到的唯一优势是通过创建窗口和文档局部变量而不是全局变量,您可以通过无法直接覆盖其中任何一个来获得一些额外的安全性,并且通过它们都是局部的也可以获得一些性能提升。

2.Why are window and document being fed in instead of just being accessed normally?

2.为什么窗口和文档被送入而不是正常访问?

Addressed above. Local variables tend to be faster, but with jit compiling these days thats becoming nominal.

上面已经解决了。局部变量往往更快,但随着 jit 编译这些天这变得名义上的。

3.Why the heck is undefined being passed in?

3.为什么要传入 undefined ?

No clue....

没有线索....

4.Is attaching the object we're creating directly to window a particularly good idea?

4.将我们正在创建的对象直接附加到窗口是一个特别好的主意吗?

Probably not, but I would still stick with Crockford's pattern as attaching the function to the window object exposes it to the rest of the global stack through the window object as opposed to exposing it through a non-standard namespace.

可能不会,但我仍然会坚持 Crockford 的模式,因为将函数附加到 window 对象会通过 window 对象将其公开给全局堆栈的其余部分,而不是通过非标准命名空间公开它。

回答by Annie

I think this is mostly for code that needs to run in multiple window contexts. Say you have a complex application with lots of iframes and/or child windows. They all need to run the code in MyObject, but you only want to load it once. So you load it in whatever window/frame you choose, but you create a MyObject for each window/frame with references to the proper window and document.

我认为这主要用于需要在多个窗口上下文中运行的代码。假设您有一个包含大量 iframe 和/或子窗口的复杂应用程序。它们都需要在 MyObject 中运行代码,但您只想加载一次。因此,您可以将它加载到您选择的任何窗口/框架中,但是您为每个窗口/框架创建了一个 MyObject,并引用了正确的窗口和文档。

Taking an undefined argument is trying to protect against the fact that undefined can be changed:

使用 undefined 参数是为了防止 undefined 可以更改的事实:

undefined = 3;
alert(undefined);

See CMS's answer about how this improves safety.

请参阅 CMS 关于这如何提高安全性的回答。