潜在问题
上一章我们提到函数作用域的用法。
js
var a = 2;
function foo() {
var a = 3;
console.log(a); // 3
}
console.log(a); // 2
我们假若把 foo 中的内容隐藏起来,如下:
js
var a = 2;
function foo() { ... }
console.log(a); // 2
发现在全局作用域中,多了一个 foo。
也就是说,我们本意是想隐藏 foo 中的内容,但却无意在全局作用域中新增一个具名函数。
如果函数不需要函数名(或者至少函数名可以不污染所在作用域),并且能够自动运行,这将会更加理想。
立即执行函数
js
var a = 2;
(function foo() {
var a = 3;
console.log( a ); // 3
})();
console.log( a ); // 2
在给原先的 foo 函数外层加上两个括号之后,可见 foo 函数被包含在了一对()内部,此时function foo
成为了一个 表达式 ,末尾的()代表 立即执行。
这就是IIFE,立即执行函数表达式。
remind:它是一个表达式啊。
这里我补充一下关于函数表达式和函数声明的区别啊。
先看个 case。
js
// 1
var foo = function(){
console.log(1);
}();
// 2
function(){
console.log(2);
}();
// 3
function foo(){
console.log(3);
}();
执行结果如下:
后两个报错的原因是,不能在定义函数后马上调用。
第一个 case 不是函数声明,而是函数表达式。
js
// 函数声明
function fn() {};
// 函数表达式
var fn = function (){};
IIFE的进阶用法
定义函数并传参
js
var a = 2;
(function fn(global){ // 入参命名为 global
// ...
console.log(global.a); // 2 --- 这里的 global 就是传入的 window
})(window);
在代码风格上,对 window 对象的引用比默认打印全局变量更加清晰。
虽然这么看着其实直接打印window.a
也不是不行啊...
改变代码执行顺序
这种作用风格在 UMD 中比较常用。看看就行。
就拿书里面的来举例子吧:
js
var a = 2;
(function IIFE(def) {
def(window); // 把 window 对象传给 def
})(function def(global){ // 在第二个括号里定义函数 def
var a = 3;
console.log(a);
console.log(global.a); // 2
});
看着真的很绕啊,虽然我也是真的不理解这样写有什么意义...
以后有机会遇见了这样的写法回来更文吧(汗流浃背了😥)
小结
今天收获最有含金量的小点就是区分函数声明和函数表达式。
明天也会继续挖宝藏哒!