;(function(window, angular, document){
函数体;
})(window, window.angular, document);
一、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 () {
//
});
======================================================================================================================================================================