已知函数有3种形式:
- 函数声明(带函数名): function fn( ) {...}
- 匿名函数(不带函数名):function( ) {...} (直接在.js 文件里这样写会报错,因为js 引擎不知道你要干嘛,也不存,也不执行d)
- 函数表达式(将匿名函数存在某变量中): const fn = function ( ) {...}
2种立即执行函数:
- (function (y) {...} )(x);
- (function (y) {...} (x));
// 相当于创建一个匿名函数,存在临时变量里,然后执行这个临时变量.
// () 起的作用是告诉 js 引擎这是一个表达式
var temp = function(y) {...};
temp(x); 闭包
闭包是为了让内部函数访问外部函数里定义的变量
经典问题是这样的:
for (var i = 0; i < 3; i++) {// output 3,3,3
setTimeout(function () {
console.log(i);
}, 1000);
}这是怎么回事呢?
1秒后,setTimeout 内函数执行时,需要打印 i,js 层层向外找 i 的作用域,发现是在 for (var i...) 的时候声明的,i 的作用域是 window (var 是往外找 function, 一直找到window 层;let 是往外找到{ } 层),这个时候,i 的值已经自增到 3,所以输出 3,3,3。
下面改写一下:
for (var i = 0; i < 3; i++) { // 3,3,3
(function () {
setTimeout(function () {
console.log(i);
}, 1000)
})(i);
}发现输出还是3,3,3,怎么回事呢?是套了一层立即执行函数没错,但是到1秒后console.log打印的时候,仍然是打印变量 i,那就必须层层向外找 i 的作用域,发现还是 window,这时 i 已经变成 3了。
再改写一下:
for (var i = 0; i < 3; i++) { // 0,1,2
(function (j) {
setTimeout(function () {
console.log(j);
}, 1000)
})(i);
}输出 0,1,2, 怎么回事呢?1秒后console.log打印的时候,发现是要打印 j,层层往外找 j 的作用域,发现是 function (j)。参考上面谈到的立即执行函数,实际上,for 循环过程,产生了3 个临时变量(封存了函数表达式),i 的即时值传给了j
function (j=0)(setTimeout(...)),
function (j=1)(setTimeout(...)),
function (j=2)(setTimeout(...)).
当然,以上代码段写成这样也行:
for (var i = 0; i < 3; i++) { // 0,1,2
(function (j) {
setTimeout(function () {
console.log(j);
}, 1000)
}(i));
}下面再来看es6 的let
// 把第一段代码的 var i 变成 let i
for (let i = 0; i < 3; i++) {// output 0,1,2
setTimeout(function () {
console.log(i);
}, 1000);
}输出 0,1,2, 为什么呢?let 的作用域是往外找到最近一层{ },于是console.log 打印的时候层层向外找 i,找到for(){} 花括号的地方(不同于 var 找的是function, var 的话最后找到的是window 层)。效果类似于下面这一段:
for (var i = 0; i < 3; i++) {// output 0,1,2
const fn = function() {
var j = i;
setTimeout(function () {
console.log(j);
}, 1000);
};
fn();
}(以上是个人理解,欢迎指正)
(时值SARI,师兄师姐去武汉上前线了,闺蜜也上前线了,广东省定点医院,网上还有人说风凉话,我心好痛,好乱,如有词不达意,见谅。
并请大家多多支持医生,他们是英雄!
如果做不到,请务必保证个人安全,出门戴口罩,回家洗手消毒,不让自己成为移动传染源,医生够忙的了。
天佑湖北,天佑中华)