- 在JavaScript中,每一个函数被调用时,都会创建一个新的执行上下文。因为在函数里定义的变量和函数是唯一在内部被访问的变量,为而不是在外部被访问的变量,当调用函数时, 函数提供的上下文提供了一个非常简单的方法创建私有变量。
立即执行函数
- 当圆括号出现在匿名函数的末尾调用函数时,它会默认将函数当成是函数声明。
- 当圆括号包裹函数时, 它会默认将函数作为表达式去解析,而不是函数声明。
函数声明:
function () {}(); //会报错 Function statements require a function name
function f() {}();//不报错,也不会执行
函数表达式:
(function() {})(); //正确执行
var foo = function () {
console.log(1111);
}(); //正确执行
true && function () {
console.log(1111);
}(); //正确执行
如果你并不关心返回值, 或者让你的代码尽可能的易读,可以在函数前面加上一个一元操作符来存储字节。
!function(){/* code */}();
~function(){/* code */}();
-function(){/* code */}();
+function(){/* code */}();
new function() {}//直接执行
new function() {}(); //仅需传递参数时才需要加括号
关于括号
- 一些情况下, 额外的带着歧义的括号围绕函数表达式是没有必要的,因为此时括号已经将其作为一个表达式进行表达; 正常情况下括号用于调用函数表达式比较常用。
- 例子中括号指明函数表达式会被立即调用, 而且变量将会存储函数的结果,而不是函数本身。当这是一个很长的函数时可以节约阅读代码的时间,不用滚动或搜索页面看清函数是否被调用。
- 作为规则,当写清楚清晰代码时,有必要阻止JavaScript抛出的错误, 同样也有必要阻止其他开发者对你抛出的错误。
保存闭包状态
当函数被调用时,参数会被传递, 而当函数表达式被立即调用时, 参数也会被传递。 但是一个立即调用的函数表达式可以用来锁定值并且有效的保存此时的状态, 因为任何定义在一个函数内的函数都可以使用外面函数传递进来的参数和变量(这种关系被叫做闭包)。
举个lockedIndex的例子:
var elems = document.getElementsByTagName('a');
for(var i = 0;i < elems.length;i++) {
(function(lockedInIndex){
elems[i].addEventListener('click',function(e){
e.preventDefault();
alert('I am link #' + lockedInIndex);
},false)
})(i);
}
立即执行函数一个最为著名的优势是,就算它没有命名或者说是匿名,函数表达式也可以在没有使用标识符的情况下被立即调用, 一个闭包也可以在没有当前变量污染的情况下被使用。
自执行函数
1. 递归调用自己
function foo() {foo()};
2. 自执行匿名函数 (因为她没有表示符,必须使用arguments.callee来调用自己)
(function() {arguments.callee();})
3. 自执行匿名函数,但是foo标识符作为它的引用时,可用foo来调用
var foo = function() {foo();};
模块模式
- 返回值用对象代替了函数
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function(val){
i = val;
},
increment: function(){
return ++i;
}
}
}());
counter.get();//0
counter.set(3);
counter.increment();//4
counter.increment();//5
conuter.i;//undefined (`i` is not a property of the returned object)
i;//ReferenceError: i is not defined (it only exists inside the closure)
- 模块模式方法不仅相当的简单厉害。非常少的代码,你可以有效的利用与方法属性相关命名,在一个对象里,组织全部的模块化代码即最小化了全局变量的污染也创造了使用变量。