文章目录
前言
前一段时间学习了ES6的语法,关于新增的let和const不太理解,故将之前的笔记再次整理如下。分别讨论下var let const
作用域
在介绍let,var,const的区别的时候,我们首先要介绍一个概念,作用域。
作用域:可访问变量的合集,包括函数,变量,对象的集合。
在ES5中我们只有两种作用域,局部作用域和函数作用域。给我们写代码带来了一些问题。
没有块级作用域带来的问题
1. 内层变量会覆盖掉外层变量
在上图中,f()执行为undefined的原因就是:变量的提升导致内层的变量覆盖掉了外部的变量,注意:**变量的声明会提升,但是定义不会提升。**所以尽管,var temp;
提升了,但是temp = "我是内部的哦"
并没有提升,所以输出的时候,temp并没有赋值,输出为undefined
2. 用来计数的循环变量会泄露为全局变量
根据上述问题,在ES6中新增了块级作用域(即let定义的变量会绑定一个块级作用域)
在这里,最后输出的结果为10,变量i虽然只是一个计数器,但是在循环结束后,并没有消失,所以泄露为全局变量,所以输出10。
为了改变这种影响,所以新增了let
var
var是js中我们最常见的一个变量声明的方法,经常用来定义一个变量。
var a = 13;
let
let为js新增了块级作用域。
在这里执行函数,输出的就是外部变量,这里有let声明了两个n,但最后输出的为外部的,这就表明外层的代码块不受内部的影响,但如果我们用var 定义变量,输出的就是内部的哦。
如上图所示,如果都用var定义,就会输出内部变量。
如果var 定义在外部,let定义在内部,仍会输出“我是外部的哦”
但是如果var定义在内部,let定义在外部,就会报错,因为
let 和 var的比较
通过下面两块代码,我们来具体分析:let和var的区别。
会依次输出0,1,2,2
首先setTimeout异步执行就不多说了。
因为let会绑定一个块级作用域,每次执行一次循环的时候就会绑定一个块级作用域,就会把当前值绑定给一个函数,所以第一次执行的时候,绑定了0,第二次执行的时候绑定了1。
var 因为不存在块级作用域,所以会导致变量泄露,当跳出循环的时候,i=2,所以输出的两次均为2。
const
const声明的常量数值不能改变。
const也只能在块级作用域访问,而且const声明的常量,其值不能改变。相比于let,只是值能不能改变的区别。
如下图所示,就会报错。
const声明复合型变量。
但有个例外,const声明的对象·,可以改变其属性值,例如:
但是直接改变fruit就会报错:
原因:**对于复合型的变量,变量名不指向数据,而是指向数据所在的地址,const命令只能保证变量名指向的地址不变,并不能保证该地址的数据不变。**在这里,fruit存储的是一个地址,指向一个对象,不可变的是这个地址,就是说不能把fruit指向另一个地址,但是对象本身是可变的,所以依然可以为其添加新的属性。
下面还有一个例子,const声明一个数组。
a.push()和a.length都可以执行,因为数组是可写的,但是不能给a赋值一个新的数组,会报错。
如果想要冻结变量,可以使用Object.freeze。对象的属性也可以冻结。
冻结对象:
var fruit = Object.freeze({});
fruit.prop("123");//不起作用
冻结属性:
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
const声明后,就必须马上初始化。
const声明常量后,必须马上初始化,不能留到以后赋值,否则便会报错。
const只在声明所在的块级作用域内有效
const声明的变量不存在变量提升
const命令声明的变量不会进行提升,会存在暂时性死区,只能在声明后使用。
const也不能重复声明常量(同let一样)
let和const比较
let和const相比,除了const声明的常量值无法改变,其余都一样。