What (function (window, undefined) {})(window);really means

如果你看过jQuery/angularJS等一些库的源码,是不是会经常看到如下的形式:

(function( window, angular, undefined ) {
    //do something
})(window, window.angular);

为什么要这么写呢?这么写有哪些好处,下面我们将一一论述:

一、Scope

我们知道,Javascript是函数作用域,因此,这么写创建了一个“私有作用域”。例如:

(function (window, document, undefined) {
  var name = 'Todd';
})(window, document);

console.log(name); // name is not defined, it's in a different scope

二、How it works

 一个普通的函数看起来像这样:

var logMyName = function (name) {
  console.log(name);
};

logMyName('Todd');

我们能够在作用域下的任何一处调用它。

我们如何让上面的函数在运行时能立即调用呢?可以像下面这样:

var logMyName = (function (name) {
  console.log(name); // Benjamin
})('Benjamin');

立即函数的定义像下面这样:

(function () {
  
})();

额外的圆括号是必须的,但是下面的代码会报错:

function () {
  //Uncaught SyntaxError: Unexpected token ( 
}();

虽然几种怪异的写法能欺骗javascript “making it work”,这些迫使JavaScript分析器对待下面的代码中的“!”字符作为一个表达式:

!function () {
  
}();

还有一些其他的变种:

+function () {
  
}();
-function () {
  
}();
~function () {
  
}();

当然我们不会使用它们,如果你感兴趣可以运行下它们都输出为何值?

三、Arguments

 现在我们已经知道它是如何工作的了,我能传递参数到立即函数中。

(function (window) {
  
})(window);

在函数运行时我们传递一个window对象,接收的参数名称也命名为window,你可能觉得不好,但是现在也使用window。
我们还可以传入文档对象document,像下面这样:

(function (window, document) {
  // we refer to window and document normally
})(window, document);

熟悉原型链的同学都知道,访问局部变量肯定比访问全局变量速度快,如果一个程序中大规模的访问全局变量,那性能问题是值得我们考虑的。

四、What about undefined?

 在Ecmascript 3中,undefined是可变的,不是关键字,这意味着它的值可以被覆盖或者重新赋值。如undefined = true。值得庆幸的是,在ECMASCRIPT 5严格模式(’use strict';)中解析器将抛出一个类型错误。因此我们需要保护我们的undefined,像下面这样:

(function (window, document, undefined) {

})(window, document);

这意味着,如果有人重新定义了undefined,对我们也是么有影响的,想下面这样:

undefined = true;
(function (window, document, undefined) {
  // undefined is a local undefined variable
})(window, document);

五、Minifying

使用立即函数的形式,在我们压缩代码时会更容易的:

(function (window, document, undefined) {
  console.log(window); // Object window
})(window, document);

改变如下:

(function (a, b, c) {
  console.log(a); // Object window
})(window, document);

想象一下,所有的形参、window、document都能被很好的压缩,当然像使用jQuery时常用$,同时我们可以使用其他的代替:

(function ($, window, document, undefined) {
  // use $ to refer to jQuery
  // $(document).addClass('test');
})(jQuery, window, document);

(function (a, b, c, d) {
  // becomes
  // a(c).addClass('test');
})(jQuery, window, document);

这也意味着你不要使用jQuery.noConflict();当引用不同的库发生$冲突时。
当然,一个好的minifier将确保重命名undefined to c。重要的是要注意,这和undefined的名称是不相关的。我们只需要知道该引用对象是undefined,因为undefined没有特殊的含义 – undefined是javascript分配给未定义变量的值。

六、Non-browser global environments

 当在非浏览器环境中,如nodejs,为了适应多种环境,我们定义立即函数像如下这样:

 

(function (root) {

})(this);

下面是一个通用的解决方案,在不同的环境中:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory); //requireJS
  } else if (typeof exports === 'object') {
    module.exports = factory; //as nodejs
  } else {
    root.MYMODULE = factory(); //in borwser
  }
})(this, function () {
  // 
});

 

 英语原文:https://toddmotto.com/what-function-window-document-undefined-iife-really-means/

 

posted @ 2016-01-22 09:51  赵小磊  阅读(256)  评论(0)    收藏  举报
回到头部