咱们知道es5中 var
声明变量是做用于在全局或函数做用域,而且全局声明的变量还会做为 window
对象的属性。这样会增长程序错误的产生和不可控。es6
在全局或者函数做用内用 var
声明的变量,在js预编译阶段会提高到当前做用域的顶部,这就是变量提高。以下代码:函数
function getValue(condition) {
if (condition) {
var value = 'red';
} else {
console.log(value); // undefined
}
console.log(value); // undefined
}
复制代码
以上代码至关于把变量value放在当前做用域先声明,因此才能在if块外和else块访问到,都会输出 undefined
。post
function getValue(condition) {
var value;
if (condition) {
value = 'red';
} else {
console.log(value); // undefined
}
console.log(value); // undefined
}
复制代码
从上面的能够看出 var
声明的变量没有块级做用域的概念,因此es6引入了let
声明,并绑定在当前的块做用域,块做用域外访问报错,以下:ui
function getValue(condition) {
if (condition) {
let value = 'red';
} else {
console.log(value); // ReferenceError: value is not defined
}
console.log(value); // ReferenceError: value is not defined
}
复制代码
禁止重复声明。在同一个块中不能用 let
声明已经存在的标识符,不然会报错。若是是嵌套的做用域中重复声明,则不会报错。es5
var count = 30;
let count = 30; // SyntaxError: Identifier 'count' has already been declared
if (true) {
let count = 30; // 不会报错
}
复制代码
在es6引入const
来进行常量的声明。他和前面的 let
同样有块做用域绑定和不准重复声明的特性。可是const
必需要在声明的阶段进行初始化,而let
不用。spa
let count; // 不会报错
const count; //SyntaxError: Missing initializer in const declaration
const count = 30; // 正确声明
复制代码
const
声明的变量不能再赋值。若是变量是引用类型,能够修改对象的属性值,但不能够从新修改绑定的对象。code
const count = 20;
count = 30; // TypeError: Assignment to constant variable.
const obj = {};
obj.name = 'wozien';
复制代码
因为let
与 const
不存在变量提高,因此在声明前使用该变量会报错。由于在声明前,该变量存在于所谓的临时死区(TDZ)。对象
if (true) {
console.log(typeof value);
let value = 'red'; // ReferenceError: value is not defined
}
复制代码
当变量声明后,就会从临时死区移出,后续可正常访问。注意的是,TDZ是针对当前的块做用域而言,因此以下能够正确运行:作用域
console.log(typeof value); // undefiend
if (true) {
let value = 'red';
}
复制代码
在 var
声明的循环变量,会在循环后外部可正常访问,而且值为跳出循环的值。let
声明的变量则只在循环体内有效,以下:开发
for (var i = 0; i < 5; i++) {}
console.log(i); // 5
for (let i = 0; i < 5; i++) {}
console.log(i); // ReferenceError: i is not defined
复制代码
在利用 var
声明的循环中建立函数会变得很艰难,由于函数执行的时候是迭代完的最终,以下:
const func = [];
for (var i = 0; i < 3; i++) {
func.push(() => {
console.log(i);
});
}
func.forEach(func => func()); // 2 2 2
复制代码
咱们能够利用当即执行函数(IIFE)解决这个问题,让每一个函数最终保存的是迭代过程当中变量的副本。
for (var i = 0; i < 3; i++) {
(function(value) {
func.push(() => console.log(value));
})(i);
}
复制代码
在es6中循环里面 let
声明能够用来简化上面IIFE的实现过程,他会在每次迭代过程当中从新声明一个同名变量i,值为当前的迭代i的值,因此循环体内的函数使用的都是i值的副本。
for (let i = 0; i < 3; i++) {
func.push(() => console.log(i));
}
func.forEach(func => func()); // 0 1 2
复制代码
若是把 let
改为 const
, 在第二次迭代的时候会报错,由于 const
不准从新赋值。而对于 for-in
和 for-of
循环二者均可以正常的运行。
const obj = {
a: 1,
b: 2,
c: 3
};
const func = [];
for (let key in obj) {
func.push(() => console.log(key));
}
func.forEach(func => func()); // a b c
复制代码
若是把let
替换成 var
,将会输出3个c。由于 for-in
和 for-of
每次都只会从新声明一个新的副本key。
利用 var
在全局声明变量,会做为window对象的一个属性存在,而 let
和 const
则不会。
var a = 1;
let b = 2;
const c = 3;
console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined
复制代码
es6中的let
和 const
与 var
区别以下:
for
循环中每次建立新的副本window
属性在咱们平时的开发中,能够默认使用const
。在确认须要改变变量的值时才使用let
,能够必定程序上防止代码的错误产生。