5

我正在查看underscore.js 库的代码(jQuery 做同样的事情),只是想澄清一下为什么将窗口对象传递给自执行函数。

例如:

(function() {            //Line 6
  var root = this;       //Line 12
  //Bunch of code
}).call(this);           //Very Bottom

既然this是全局的,为什么要传递给函数呢?下面的工作也不行吗?这样做会出现什么问题?

(function() {
  var root = this;
  //Bunch of code
}).call();
4

2 回答 2

5

我怀疑原因是 ECMAScript 5 strict mode

在非严格模式下,这个 IIFE

(function() {
   console.log(this); // window or global
})();

记录window对象(或global对象,如果您在 node.js 服务器上),因为全局对象是this针对不作为对象方法运行的函数提供的。

将该结果与

"use strict";
(function() {
   console.log(this); // undefined
})();

In strict mode, the this of a bare-invoked function is undefined. Therefore, the Underscore authors use call to supply an explicit this to the anonymous function so that it is standardized across strict and non-strict mode. Simply invoking the function (as I did in my examples) or using .call() leads to an inconsistency that can be solved with .call(this).

于 2012-12-13T18:15:55.633 回答
1

jQuery 做同样的事情,您可以通过沿着这些行搜索找到关于 SO 问题的几个答案。

在局部范围内有一个始终可用的全局变量有两个原因,这两个原因window都是为了进行相当小的优化:

  1. 加载时间。查找局部变量比查找全局变量花费的时间要少一点,因为解释器不必查找上下文树那么远。在 Underscore 或 jQuery 大小的函数长度上,理论上可以在较慢的机器上加起来不​​那么微不足道的时间。

  2. 文件大小。Javascript 缩小依赖于这样一个事实,即变量可以命名任何东西,只要它们是一致的。myLongVariableName变成a缩小版。当然,问题是这只适用于脚本内定义的变量;它从外部提取的任何东西都必须保持相同的名称才能工作,因为如果您缩小windowpr解释器将不知道您在说什么。通过使用对自身的引用来遮蔽它,Minify 可以执行以下操作:

    (function(A){ B(A, {...}); A.doStuff(); //etc });})(window)
    

    每次你本来应该放window(6个字符)的时候,你现在有A(1个字符)。window同样,不是主要的,但在需要定期显式调用以进行范围管理的大文件中,它可能很重要,如果您使用它两次,您已经获得了几个字符的优势。在由有限的服务器和可能有糟糕的互联网计划的人提供服务的大型流行图书馆中,每个字节都很重要。


阅读有关问题的评论后进行编辑:

如果您查看实际function.call()执行的操作,您的第二个片段实际上不会起作用 -传入this的不是参数,它是函数的显式调用上下文,您必须将其提供给.call(). 文件开头的行用于上述两个目的。明确设置上下文的原因是面向call未来的——现在,匿名函数获取全局上下文,但理论上这可能会改变,在未来的 ECMA 规范中不鼓励使用,或者在小众浏览器上表现异常。对于一半的互联网使用的东西,最好更加明确并完全避免这个问题。this/ _window顶级选择我认为必须与担心非PC设备(即移动设备)可能会为其顶级对象使用不同的名称有关。

于 2012-12-13T18:09:31.747 回答