在es6之前,我们定义变量都是用的var的方式,但是我确实花了不少的时间理解var的变量定义方式,var定义变量的作用域是整个函数范围,而不是类似于c语言的在一个大括号内,严谨的说也就是没有所谓的“块级作用域”,这被视为是JavaScript的一个缺点,如下代码:
for(var i=0;i<3;i++)
{
setTimeout(function(){
console.log(i);
},200)
}//结果为3,3,3
在了解到闭包,垃圾回收机制之前我对这个结果并不是很理解,但是现在回过头来看就比较清晰了,当然,用到了setTimeout,就必须得先扯开一下聊聊JavaScript的语言特性,首先
它是一门单线程,异步的语言,所谓单线程,就是说JavaScript只能再一个时间内做一件事,举个实际的例子来说,昨天早上我起床叫我室友打LOL,他先起床,后刷牙,耗时7分钟,最后打开电脑等待游戏登陆的3分钟,总耗时10分钟。这样明显会使得做事的效率明显比较低,于是他今天早上学聪明了,起床直接打开游戏登陆,再去刷牙,只用了7分钟,节约了3分钟宝贵的游戏时间,这也就是“异步操作”。那么JavaScript到底是如何做到的呢,实际上,JavaScript,c语言(其他语言我也不晓得~~)的函数的编译原理都是基于“堆栈”这种数据结构的,编译器会把需要执行的函数放入stack中执行则入栈,return则出栈,所以对于某些函数,方法,JavaScript会让它处于等待状态,不会等到它出栈后再让后续函数入栈。
其次:
在JavaScript中有垃圾回收机制,由于对地址的回收,类似于c语言的free函数,至少对于初学者,这是一个优点,但是便利的结果往往是更加纠结,关于这个有趣的机制MDN给出了详细的解释
由此可见,在我们给出的这个例子里,i实际上是一个引用也就是指针,for循环先执行完毕后定时器函数执行,当定时器函数执行时,由于它的内部没有定义i,所以他会沿着他的作用域链寻找i,而此时for循环已经被垃圾回收了,所以i最后的值为for循环结束累加的值;
如何解决这个问题呢,此前我们会利用闭包的方法,将函数嵌套,让i存在引用的对象,也就不会被垃圾回收了,代码如下:
for(var i=0;i<3;i++){
(function(){
var fn1=(x)=>{
console.log(x);
}
return fn1(i);
})()
}//0,1,2
var某些特性解释让代码看起来如此复杂~~~;
那么let将如何解决这个问题呢?
for(let i=0;i<3;i++){
setTimeout(function(){
console.log(i);
})
}//0,1,2
是不是感觉柳暗花明又一村的,和c语言写循环是一样的,明显的感觉到JavaScript与其他语言相比其独具风格的地方在变少;
综上所述:
let,const的与var的区别在于,var的作用域在整个函数,而前者的作用域仅在父级的大括号;
当然还有其他的小区别:
1:var 会在定义的函数未执行时就被找到,如
alert(i);//undefined
var i=2;
而换成let const就会报错
2: const 定义的变量为常量,不可以改变,会报错,同样用let重定义变量会抛出一个语法错误;
3:形如for (let x...)的循环在每次迭代时都为x创建新的绑定。
/*也就是说循环创建的每一个i并不等效,i的值的改变并不是在单纯的在原引用上改变;
参考资料
深入浅出ES6(十四):let和const_JavaScript_Jason Orendorff_InfoQ精选文章
js中的同步和异步的个人理解_js什么是同步什么是异步_YinghaoGuo的博客-CSDN博客
---------------------文章转载至: 用月光取暖----------------------------