前言
本文适用于拥有ES5基础的读者。 本文将要介绍ES6新增的的两个变量 let 和 const。
正文
1.在ES6之前的变量声明会被提升到作用域顶端,而ES6新增的变量声明并不会被提升到作用域顶端。ES6的变量声明是块级声明。
回顾一下关键字var 声明变量,使用var声明变量,无论实际声明的位置在哪里(变量声明会被提升到作用域的顶端),都会被视为声明在所在函数的顶部。
例如:
function getValue(condition){
if(condition){
var value = 1;
return value;
}else{
return null;
//value 在此处可以访问,值为undefined;因为value这个变量会被提到作用域的顶端。
}
//value 在此处可以访问,值为undefined;因为value这个变量会被提到作用域的顶端。
}
ES6 新增的let 和 const
let 和 const 均为块级声明,所声明的变量在指定的块级作用域(词法作用域)之外无法访问,不会把变量声明提升到作用域的顶端。
function getValue(condition){
if(condition){
let value = 1;
return value;
}else{
return null;
//value 此处不可访问
}
//value 此处不可访问
}
2.ES6之前的变量都可以重复声明,而ES6新增的变量不能重复声明。
var 可以重复声明,只不过后面的会覆盖前面的。
而 let 和 const 不可以在同一作用域里面重复声明,否则则会报错。
var a = 1;
var a = 10;
// a =10
let b = 1;
let b = 10;
// Uncaught SyntaxError: Identifier 'b' has already been declared
const c = 1;
const c = 10;
// Uncaught SyntaxError: Identifier 'c' has already been declared
此处特别注意出现语法解析错误(SyntaxError)时,出现错误的那行之后都不会再运行下去。
在不同作用域则不会报错,会屏蔽全局变量。
var a = 1;
if (2 > 1) {
let a = 2;
// 屏蔽全局
}
3.在ES6之前的变量声明可以修改,而ES6新增的变量声明并不能修改。
let 变量 可以修改 const 常量 不可以修改
const声明的变量被认为是常量,设置后不可修改 因此声明时需要初始化(即赋值),不初始化会报错。
const d;
//Uncaught SyntaxError: Missing initializer in const declaration
const声明的对象中的值可以修改,它本身不可以修改。
const person = {
name = "lu",
age = 10
}
person.age = 12;
// age = 12
person = {
name = "liu",
age = 13
}
//Uncaught SyntaxError: Invalid shorthand property initializer
4.ES6之前变量未经声明可以访问,而使用ES6新增的 let 和 const 声明的变量,未经声明访问则会报错,即使使用安全的操作(typeof)。此问题称为暂时性死区 。
console.log(typeof value);
// undefined
console.log(typeof value1);
// Uncaught ReferenceError: Cannot access 'value1' before initialization
let value1 = 1;
5.var 在循环内声明变量,在循环外可以访问,因为变量会提升,而let 在循环内声明变量,在循环外不可以访问,因为它是块级变量声明,变量不会提升。
for (var i = 1; i < 10; i++) {
console.log("123");
}
console.log(i);
// 10
for (let i = 1; i < 10; i++) {
console.log("123");
}
console.log(i);
//Uncaught ReferenceError: i is not defined
const 不可以在for 循环内声明变量,因为每一次循环相当于修改其值,而const 声明的变量不可修改其值,const 可以在 for in 和 for of中声明变量,因为并没有修改其值。
for (const i = 1; i < 10; i++) {
console.log("123");
}
console.log(i);
//Uncaught TypeError: Assignment to constant variable.
var count = [];
object = {
a: 2;
b: 1;
}
for(const key in object){
count.push(function(){
console.log(key);
}
count.forEach(function(count){
count();
//依次输出 2 1
}
6.循环内的函数
var count1 = [];
for (var i = 0; i < 10; i++) {
count1.push(function() {
console.log(i);
});
}
count1.forEach(function(count1) {
count1();
//输出了 10个 10
});
在当时学习JavaScript的时候你可能会认为结果是依次输出0-9,而事实则是输出了 10个 10,因为变量i在循环的每次迭代中都被共享,意味着循环内创建的哪些函数都拥有对于同一变量的引用。这个原因大家应该还都记着。那怎么解决呢?一般当时都是采用立即执行函数的方式。
var count2 = [];
for (var i = 0; i < 10; i++) {
count2.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
count2.forEach(function(count2) {
count2();
//依次输出0 1 2 3 4 5 6 7 8 9
})
而使用ES6新增的let 则不用这么麻烦,能够简化这个循环。
var count3 = [];
for (let i = 0; i < 10; i++) {
count3.push(function() {
console.log(i);
});
}
count3.forEach(function(count3) {
count3();
// 0 1 2 3 4 5 6 7 8 9
})
在循环中let 声明 每次都创建了一个新的i变量,因此在循环内部创建的函数获得了各自的i 副本,而每个i 副本的值在每次循环迭代声明的时候被确定了。
7.var全局作用域上声明会创建一个新的全局变量,并成为 全局对象,而let 和 const 不是这样。
var a = 2;
console.log(a); // 1
console.log(window.a); //1
let b = 2
console.log(b); //2
console.log(window.b === b); //false
const b = 2
console.log(b); //2
console.log(window.b === b); //false
结语
在默认情况下使用let 比较好,因为不会出现重复声明。保护变量不被修改,使用const 比较好。本文主要介绍了ES6的变量声明。如有不当之处还请大家指出,希望关注更多,关注我哦。