使用(函数(窗口,文档,未定义){…})(窗口,文档)的优点是什么?
我认为使用这种模式是新的热点,但我不明白什么是优势,我不明白范围的影响。
模式:
(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
的名称并不意味着什么特别的,不是像true
, false
等关键字,它只是一个标识符。
只是为了logging,在ECMAScript 5中,这个属性是不可写的…
附加我们正在创build的对象直接窗口一个特别好主意?
当您处于另一个函数作用域时,这是用于声明全局属性的常用方法。
这种特殊的风格确实比“Crockford”风格带来了一些好处。 首先,传递window
和document
允许脚本被更有效地缩小。 缩小器可以将这些参数重命名为单字符名称,每个引用分别节省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如何提高安全性的答案。