您是否曾经看过jQuery 1.4源代码,并注意到它是如何通过以下方式封装的:

(function( window, undefined ) {

  //All the JQuery code here 
  ...

})(window);


我读过一篇有关JavaScript的文章Namespacing和另一个叫做“一对重要的父母”,所以我知道这里发生了什么。

但是我以前从未见过这种特殊的语法。 undefined在那做什么?为什么要传递window,然后再次出现在末尾?

评论

我想补充一下,保罗·爱尔兰(Paul Irish)在此视频中谈到了这一点:paulirish.com/2010/10-things-i-learned-from-the-jquery-source

@Bergi,您将我的问题标记为另一个问题的重复,但是在重复之前将近一年,我问了这个问题。演员阵容应该与之相反。

@dkinzer:这不是关于早些被问到,而是关于最高质量的答案。诚然,在这种情况下,并驾齐驱,但我发现CMS的答案是最好的答案。不过请访问chat.stackoverflow.com/rooms/17进行讨论

另请参见使用(function(window,document,undefined){…})(window,document)有什么好处?

#1 楼

undefined是普通变量,可以使用undefined = "new value";进行简单更改。因此,jQuery创建了一个真正的undefined本地“ undefined”变量。

出于性能原因,将window变量设置为local。因为当JavaScript查找变量时,它首先会遍历局部变量,直到找到变量名为止。当找不到它时,JavaScript将遍历下一个范围等,直到它对全局变量进行过滤。因此,如果将window变量设为本地,JavaScript可以更快地查找它。
更多信息:加快JavaScript的速度-Nicholas C. Zakas

评论


谢谢!这是一个非常有用的视频。我认为您需要编辑响应以说“ window变量设为本地”。我确实认为这是最好的答案。我数了一下,发现在JQuery源代码中窗口对象至少被调用了17次。因此,将窗口移到“本地合并范围”中将产生重大影响。

– dkinzer
2010-4-26 20:47



@DKinzer哦,是的,您是对的,当然它是本地化的。很高兴可以为您提供帮助=)

– Vincent
2010-4-27的15:00

根据此更新的测试jsperf.com/short-scope/5,通过jQuery获取窗口常量时,传递“窗口”实际上要慢一些,这对Safari尤其不利。因此,尽管“未定义”有一个用例,但我不太相信“窗口”在所有情况下都特别有用。

– hexalys
13年4月28日在10:38

这对于减少代码也有积极作用。因此,最小化器可以用较短的名称替换“窗口”和“未定义”的每种用法。

–TLindig
13年6月6日在8:05

@ lukas.pukenis当您要建立数以百万计的网站使用的图书馆时,明智的做法是不要对疯子的行为做出假设。

– JLRishe
2014年9月1日在18:56

#2 楼

未定义

通过将undefined声明为参数,但从不传递任何值,可以确保始终未定义,因为它只是全局范围内的变量,可以覆盖。这使a === undefined可以安全替代typeof a == 'undefined',从而节省了一些字符。它还使代码更加简化,例如可以将undefined缩短为u,从而节省更多字符。

Window

window作为参数传递可以保持在本地范围内复制,这会影响性能:http://jsperf.com/short-scope。现在,对window的所有访问都必须在范围链上移动一级。与undefined一样,本地副本再次允许更积极的缩小。


旁注: window中的允许将该库更轻松地集成到服务器端Javascript环境中,例如node.js-其中没有全局window对象。在这种情况下,只需更改一行即可将window对象替换为另一行。对于jQuery,可以创建一个模拟的window对象并将其传入以进行HTML抓取(jsdom之类的库可以做到这一点)。

评论


+1代表Minification,希望我能为jsperf +2-最小版本为(function(a,b){})(window); -a和b比window短得多并且未定义:)

– gnarf
2011-2-9 13:25



+1我之前听说过作用域链,但是忘记了这个词。谢谢!

– alex
2011-2-9 13:25

这也是使用void(0)的另一种选择,它的意思是出于相同的原因:void(0)是获取未定义值的安全方法。

– glmxndr
2011-2-9 13:26

“您所说的”是指另一个问题:stackoverflow.com/questions/4945265/…

– gnarf
2011-2-9 13:46

@gnarf,感谢您提出问题合并的通知。我将编辑我的答案以使其更有意义;)

–大卫·唐(David Tang)
2011-2-9 13:48

#3 楼

其他人已经解释了。 undefined就像可以重新定义为任何值的全局变量。如果有人在某处写了“ undefined”,此技术可以防止所有未定义的检查都中断。不管变量undefined = 10的值如何,保证永远不会传递的参数是真实的undefined

可以通过以下示例说明传递窗口的原因。
(function() {
   console.log(window);
   ...
   ...
   ...
   var window = 10;
})();


控制台记录什么? undefined对象的值对吗?错误! 10个?错误!它记录window。 Javascript解释器(或JIT编译器)以这种方式重写它-

(function() {
   var window; //and every other var in this function

   console.log(window);
   ...
   ...
   ...
   window = 10;

})();


但是,如果将undefined变量作为参数,则不会有var,因此不会感到意外。

我不知道jQuery是否正在执行此操作,但是如果出于某种原因要在函数中的任何位置重新定义window局部变量,则最好从全局范围中借用它。 >

#4 楼

window是这样传入的,以防万一某人决定在IE中重新定义窗口对象,我假设undefined也是一样,以防以后以某种方式重新分配。
脚本只是将参数命名为“ window”,该参数比全局window引用更本地化,并且此闭包内部的代码将使用什么。最后的window实际上指定了第一个参数要传递的内容,在这种情况下,是window的当前含义...希望您在此之前不会搞砸window

此通过显示在jQuery中使用的最典型的情况,插件window处理,可能会更容易想到,因此对于大多数代码,您仍然可以使用.noConflict(),即使它意味着超出此范围的$之外:

(function($) {
  //inside here, $ == jQuery, it was passed as the first argument
})(jQuery);


评论


谢谢。这很有道理。虽然,我认为答案是这与@ C.Zakas说的结合。

– dkinzer
2010-4-26 20:50



@DKinzer恐怕我不是C.扎卡斯;)

– Vincent
2010-4-27的15:02

@Vincent,对此感到抱歉:-)

– dkinzer
2010-4-27的15:14

#5 楼

经过1000000次迭代测试。这种本地化对性能没有影响。 1000000次迭代中甚至没有一个毫秒。这根本没用。

评论


更不用说,闭包包含所有变量以及函数实例,因此,如果闭包中有100个字节,而1000个实例中有100kb的更多内存。

– Akash Kava
13年7月31日在8:50

@AkashKava和@Semra,我认为此测试不能真正解释为什么您会在现实世界中通过窗口。仅当您具有深度嵌套的闭包(沿范围链进一步访问该变量)时,才能看到性能提升。显然,如果您的函数与变量在作用域链上仅相距仅一步之遥,您将不会获得太多收益。但是如果它在下面,并且需要打开窗口,您可能会看到本地副本有所帮助。

– Gabereal
2014年12月2日在21:42

@gabereal新的JavaScript引擎会在编译时自行解决闭包,在运行时闭包不会提高性能。我怀疑是否会有可衡量的性能提升,如果您如此有信心,可以创建jsperf示例来演示性能。我们获得的唯一性能是隔离闭包,从而实现更好的缩小效果,从而减小大小,并通过更快的脚本下载和解析来实现性能。

– Akash Kava
2014年12月4日上午10:59

@AkashKava是什么让您觉得我很自信?我只是说“可能会有所收获”和“我不认为”。我可以创建一个测试,但是我宁愿不这样做,因为我从不使用这种模式。您能否解释“在编译时解析闭包”的含义?相对于其他选择呢? JavaScript引擎之前的功能有何不同?

– Gabereal
2014年12月4日21:36

找到一个代码,该代码在最后固化窗口但未在函数的参数中输入,这是什么意思?它确保即使我假设没有任何窗口参数,参数也可以遵循原始全局范围对象。

– Webwoman
19年1月22日在23:10