首先来了解一下let与var的区别,主要有一下三点:
第一点,var在javascript中是支持预解析的,而let不支持预解析,代码如图:
执行结果如图:
结果未报错,下面将var换成let,代码如下:
执行结果:
错误提示为:Uncaught ReferenceError: a is not defined,翻译成中文大概意思就是a未定义。这与undefined是不同的,undefined是未赋值,但已经定义了。
第二点:var可以重复定义同一个变量,但是let不可以,看代码:
执行结果如图:
结果没有报错,将var换成let:
执行结果为:
错误信息为:Uncaught SyntaxError: Identifier 'a' has already been declared。翻译为中文,意思是a已经被定义。
第三点:let可以形成块级作用域,在es6之前javascript只有函数作用域,没有块级作用域。那在es6之前我们是怎么实现块级作用域的呢?有朋友已经猜到了,立即执行函数表达式,简称IIFF。看代码:
执行结果为:
可以看到通过一个立即执行函数表达式,我们实现了一个局部作用域或者块级作用域,但是有了let之后就不需要写这样的代码了,代码修改如下。
执行结果:
可以看到两者实现的效果是一样的。
下面看一道经典面试题:
说出以上代码的执行结果,并解释其原理。将其改造为,依次输出0,1,2,3,4
首先上面的代码执行结果为:每隔200ms依次打印5,一共打印5次。
结果为什么是这样的呢?这里面涉及里javascript里面的两个知识点,作用域和定时器setTimeout回调函数异步执行。这段代码用var声明了一个全局变量i,循环执行完成之后,i变为5,此时javascript主线程空闲,异步回调队列中的函数依次被eventloop放进主线程执行,因为此时的i已经变为了5,所以打印了5次5。
以上便是这道题目的前两点的解析。那第三点,该如何改造代码呢?
明白了原理就好改造了,既然定时器的回调函数中的i每次都是从全局作用域中取值,能不能在循环的时候将其放到局部作用域中呢,当然可以看代码:
执行结果为:
那这些和let有什么关系呢?回忆一下let和var的第三点不同,let可以生成局部作用域,代码再次改造:
执行结果为:
以上便是let和var的不同,如果大家还有补充欢迎留言。
下面是const与var的不同,以上三点完全适用const,但是const与let或是var还有两点不同。
首先是第一点,const是用来定义常量的,常量定义之后是不允许改变的。看代码:
执行结果:
错误提示为:Uncaught TypeError: Assignment to constant variable.意思是常量已经赋值了。
这里有一个小坑,看如下代码:
来看看执行结果,看看和你心理预期是否一致。
没有报错?为什么 ?因为a的值并没有改变,依然指向刚开始赋值的那个对象,并为重新赋值,如果将a重新赋值,就会报错了。大家可以试试。用const定义的常量只要是引用类型数据,改变这个引用类型数据的结构或属性,都是允许的。引用类型包括哪些呢?数组和对象。
第二点是用const定义常量必须赋值。不赋值的话,没有任何意思,所以报错,看代码:
执行结果为:
错误提示为:Uncaught SyntaxError: Missing initializer in const declaration。意思是缺少初识值。
以上便是let const 和var的区别。大家有不明白的或者有补充的可以给我留言。