今天学习了JS的函数内容。知道每个JS函数都有调用时机。一些简单代码还是比较好理解的,但是如果碰到一些稍微复杂的代码,就需要结合闭包等其他概念来进行理解了。下面看一个例子:
let i = 0
for(i = 0; i < 6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
这个例子会输出6个6。为什么?setTimeout()
这个函数的意思是过一会儿执行。也就是说,在上面这一段代码里的意思是,过一会儿打印出i的值。但是一共执行了6次,而过一会儿i就变成了6,所以会打印出6个6。但是为什么过一会儿取的是6这个值呢?这就要从如何实现闭包说起了。
JS 的闭包
JS 实现闭包的时候,是capture variable的。意思就是,当一个闭包引用了外部变量,它就把这个变量名记下来,等到需要用到的时候,用这个变量名,去查这个变量值是多少。
其他某些语言的闭包
而有一些语言,是另外一种策略,是capture value的。意思就是,当一个闭包引用了外部变量,当这个闭包创建的那一刻,立刻查询那个外部变量的值是多少。把这个值固化下来。那么在那之后,到下一次闭包建立之前,不管这个外部变量变成了多少,都跟这个闭包无关了。
区别
他们本质上最大的区别,就是这些闭包是否可以通过某一个相同的“变量”来共享状态。capture variable 可以,但是capture value 不行。
所以,我们上面这段代码,就会输出6个6。那么,怎么让它输出0,1,2,3,4,5呢?
方法一
for(let i = 0; i < 6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
我们只需要将let声明放到里面,那么输出的就是,0,1,2,3,4,5。原因上面已经解释了。
既然如此,我们还有没有其他除了用let+for循环以外的方法让我们得到这个结果呢。
方法二
let i
for(i = 0; i<6; i++){
let x = i
setTimeout(()=>{
console.log(x)
})
}
引入另外一个变量,将i的值赋值给这个变量,之后这个变量值怎么变化就与i之后的变化无关了。
方法三
let i
for(i = 0; i<6; i++){
setTimeout((value)=>{
console.log(value)
},0,i)
}
利用setTimeout()函数的第三个参数,将i的值传入到函数中,那么之后就是输出i当时传进来时候的值,并不会跟随她之后的值而改变。
方法四
let i
for(i = 0; i<6; i++){
!function(j){
setTimeout(()=>{
console.log(j)
},0)
}(i)
}
使用立即执行函数,每次循环,就会立马执行这个匿名函数。所以匿名函数执行完之后,里面的j就确定了,之后就是过一会儿输出这个值的问题,就与之前的i怎么变化没有关系了。
这些就是我能找到的方法了,至于还有没有其他的,暂时是没找到,如果找到了再进行补充。