使用(函数(窗口,文档,未定义){…})(窗口,文档)的优点是什么?

我认为使用这种模式是新的热点,但我不明白什么是优势,我不明白范围的影响。

模式:

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

所以我有几个关于这方面的问题。

封装这样的对象是否有特别的优势?
为什么窗口文档被传入而不是被正常访问呢?
为什么heck被undefined传入?
附加我们正在创build的对象直接窗口一个特别好主意?

我习惯了我称之为Javascript封装的Crockford风格(因为我从道格拉斯·克罗克福德的Javascriptvideo中得到了它)。

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

这些模式之一在function上是否比其他模式好? 第一个是另一个的演变吗?

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

通常要加紧标识符parsing过程,把它们作为局部variables可以帮助(尽pipeIMO的性能改进可以忽略不计)。

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

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

为什么heck被undefined传入?

这是因为ECMAScript 3中的undefined全局属性是可变的,这意味着有人可以改变它的影响你的代码的价值,例如:

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

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

在JavaScript中undefined的名称并不意味着什么特别的,不是像truefalse等关键字,它只是一个标识符。

只是为了logging,在ECMAScript 5中,这个属性是不可写的…

附加我们正在创build的对象直接窗口一个特别好主意?

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

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

另外,你确实得到了执行速度的好处。 当我第一次读到@joekarl的主张,即它提供了一个性能上的好处时,我想,“这似乎相当虚假”。 所以我用一个testing页面来描述实际的性能。 参考window 一亿次,Firefox 3.6中的局部variables参考提供了适度的20%的速度提升(4200毫秒到3400毫秒),在Chrome 9中提高了31,000%(13秒到400毫秒)。

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

为什么heck被undefined传入?

因为(如@CMS所提到的) undefined的标记实际上是未定义的 。 与null不同,它没有特别的含义,你可以像任何其他variables名称一样自由地分配这个标识符。 (但是请注意, 在ECMAScript 5中这不再是正确的 。)

附加我们正在创build的对象直接窗口一个特别好主意?

window对象是全局作用域,所以这就是你在某个时刻所做的事情,无论你是否明确写出“窗口”。 window.Namespace = {};Namespace = {}; 是等同的。

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

回答你的问题

1.封装这样一个对象是否有特别的优势?

我能看到的唯一优点是通过制作窗口和文档局部variables而不是全局variables,您可以通过不能直接覆盖任何一个而增加安全性,并且由于它们都是本地的,所以可以获得一些性能增益。

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

上面解释。 局部variables往往会更快,但是这些日子里,jit编译成为名义上的。

3.为什么heck被undefined传入?

没有线索….

4.是否附上我们正在创build的对象来创build一个特别好的想法?

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

我认为这主要是针对需要在多个窗口上下文中运行的代码。 假设你有一个复杂的应用程序,有很多的iframe和/或子窗口。 他们都需要在MyObject中运行代码,但是只需要加载一次。 因此,您可以将其加载到您select的任何窗口/框架中,但是会为每个窗口/框架创build一个MyObject,并引用相应的窗口和文档。

采取一个未定义的论点是为了防止undefined可以改变的事实:

 undefined = 3; alert(undefined); 

查看CMS如何提高安全性的答案。