ES6新特性总结let及const
Posted 橘猫吃不胖~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6新特性总结let及const相关的知识,希望对你有一定的参考价值。
ES6新特性总结(1)let及const
1 let和const出现的原因
let和const是ES6新增的两种新的声明格式,用于补全ES5标准中var声明变量的不足。
var声明变量的不足:在javascript中用"var"来声明变量会出现变量提升的情况,即通过"var"声明的变量,系统都会把声明隐式的升至顶部,这样的特性往往会让刚接触JavaScript及习惯其他语言的开发人员不适应,导致程序出现问题。
例如,在下面的代码中,首先输出a,然后再用var定义a,结果并不会报错,而是输出undefined:
console.log(a); //输出undefined
var a = 9;
这是因为var声明的变量会提升到全局进行预解析,因此预解析的结果为:
var a; //undefined
console.log(a);
a = 9;
但是使用let或者const进行声明变量就不会出现这样的问题,而是会直接报错:
console.log(a); //程序报错
let a = 9;
console.log(a); //程序报错
const a = 9;
因此let和const补全了ES5标准中声明变量的不足。
2 作用域
ES5中定义作用域有两种:全局作用域和函数作用域。ES6中新增了块级作用域,用" "表示。
块级作用域用于声明作用域之外无法访问的变量,主要有两种:
(1)函数内部块级作用域
function test()
let a = 20;
console.log(a);
test(); //调用test()方法输出a=20
console.log(a); //访问不到test()函数内的a,因此会报错
(2)在字符 之间的区域
let a = 10;
console.log(a); //访问不到块级作用域中的a,程序报错
再看一个例子,在下面的循环中,当sum定义在for循环内部时,是无法输出sum的值的,程序会报错:
for (let i = 0; i < 100; i++)
let sum = 0;
sum = sum + i;
console.log(sum);//sum is not defined
因此我们需要将sum定义到for循环的外部,才能有效地执行该循环。
3 const命令
使用const声明的是常量,常量的值不能通过重新赋值来改变,并且不能重新声明,所以每次通过const来声明的常量必须进行初始化。
与其他语言不同,const在使用过程中如果声明的是对象,需要注意是可以修改对象的属性值,但不允许修改已经声明的对象。
const obj =
name: "橘猫吃不胖",
age: 2
obj.name = "张三"; //修改name属性值为张三
console.log(obj); //输出该对象
输出结果为: name: ‘张三’, age: 2
从上面的结果可以看出,在定义obj对象时,我为name属性定义的属性值是“橘猫吃不胖”,但是通过修改之后,name属性值成为了“张三”,因此const声明的对象可以修改对象的属性值。
但是如果要修改已经声明的对象,程序就会报错:对常数变量赋值
const obj =
name: "橘猫吃不胖",
age: 2
obj = ; //将该对象设置为空
console.log(obj);//报错:TypeError: Assignment to constant variable.
如果想让对象属性不能修改,可以借助Object.freeze
函数来冻结对象。
const obj =
name: "橘猫吃不胖",
age: 2
Object.freeze(obj); //冻结该对象
obj.name = "张三"; //修改对象的name属性值
console.log(obj); //输出该对象
结果仍然是: name: ‘橘猫吃不胖’, age: 2
通过Object.freeze冻结对象需要注意的是:不能冻结多层对象。
const obj =
name: "橘猫吃不胖",
age: 2,
family:
name: "张三",
age: 20
Object.freeze(obj); //冻结该对象
obj.family.name = "李四"; //修改obj对象中的family对象中的name属性
console.log(obj); //输出该对象
输出结果为: name: ‘橘猫吃不胖’, age: 2, family: name: ‘李四’, age: 20
解决多层冻结问题可以通过封装一个deepFreeze函数来实现:
function deepFreeze(obj)
Object.freeze(obj); //冻结输入的对象
for (let key in obj) //key代表了obj对象的所有属性,for...in循环会遍历该对象的所有属性
//hasOwnProperty()判断对象自身属性是否含有指定的属性
//如果对象中有一个属性,并且这个属性的类型是object,那么就冻结该属性
if (obj.hasOwnProperty(key) && typeof obj[key] === "object")
deepFreeze(obj[key]);
我们为其设计一个复杂的对象,如下所示,对象相互嵌套构成了obj对象:
const obj =
name: "张三",
age: 2,
family:
father:
address: "CSDN",
gender: "男"
,
mother:
name: "王五",
age: 26
然后尝试修改一下father对象中address属性的值:
deepFreeze(obj); //调用deepFreeze()函数,冻结obj对象
obj.family.father.address = "AAA"; //修改address属性值为“AAA”
console.log(obj); //输出修改之后的obj对象
得到的结果为:
name: ‘张三’,
age: 2,
family:
father: address: ‘CSDN’, gender: ‘男’ ,
mother: name: ‘王五’, age: 26
可以看出address属性值并未被修改,冻结成功!
4 临时死区
let和const都是块级标识符,所以let和const都是在当前代码块内有效,常量不存在变量提升的情况。但是通过let和const声明的常量,会放在临时死区(temporal dead zone)。
console.log(typeof a); //ReferenceError: Cannot access 'a' before initialization
let a = 10;
即使通过安全的typeof操作符也会报错,原因是JavaScript引擎在扫描代码变量时,要么会把变量提升至顶部,要么会把变量放在临时死区。这里通过let声明的"a"变量会被放在临时死区,所以在声明之前打印就会报错。
5 循环中let和const的使用
在ES5标准中,for循环中的循环变量都是通过var来声明的,由于var没有独立的作用域,导致在循环中创建函数时会出现结果和思路不一致的情况。
let funArr = []; //该数组中存放的是函数
for (var i = 0; i < 5; i++) //循环的次数
funArr.push(function () //添加函数
console.log(i); //输出i
)
funArr.forEach(item =>
item();
)
这段代码意味着,每循环一次,就在fuynArr数组中添加一个输出循环的次数i的函数。循环结果不是预想的0,1,2,3,4,而是5个5,这是因为var声明在循环中作用域共用,并且会把i保存在全局作用域中。
要解决循环中保存函数的问题,可以利用闭包创建独立的作用域,代码如下:
let funArr = [];//该数组中存放的是函数
for (var i = 0; i < 5; i++)
(
function (i)
funArr.push(function ()
console.log(i);
);
)(i);
funArr.forEach(item =>
item(); //输出结果为0,1,2,3,4
)
for循环中的函数被用()括起来,而且()后还有一个(i),代表了函数在定义的同时就被调用了,因此for循环中的函数每一次循环都调用,成功在最后结果中输出0,1,2,3,4,这样通过自执行函数就可以解决循环中创建函数的问题。
但利用ES6中let和const提供的快级作用域可以让代码更简洁:
let funArr = [];
for (let i = 0; i < 5; i++)
funArr.push(function ()
console.log(i);
)
funArr.forEach(item =>
item(); //输出结果为0,1,2,3,4
)
在for…in或for…of循环中使用const时,方法与let一致。
使用for…in遍历对象:
let obj =
name: "张三",
age: 20
for (const i in obj) //使用for...in遍历对象
console.log(i); //输出属性name、age
console.log(obj[i]); //输出属性值张三、20
使用for…of遍历数组:
let arr = ["张三", "李四", "王五"];
for (const i of arr)
console.log(i); //输出张三、李四、王五
以上是关于ES6新特性总结let及const的主要内容,如果未能解决你的问题,请参考以下文章