函数作用域与块级作用域
for(var i = 0;i < 5;i++) {
setTimeout(()=>{
console.log(i);//5个5
},1)
};
for(let j = 0;j < 5;j++) {
setTimeout(()=>{
console.log(j);//0,1,2,3,4
},1)
}
console.log(i);//5
console.log(j);//Uncaught ReferenceError: j is not defined
总结:var定义的变量不存在块级作用域,只有函数作用域。而let,const定义的函数具有块级作用域,且不能在同一作用域中重复声明。
思考 :为什么使用let定义的循环,再延时执行后,能依次打印出0,1,2,3,4?
for(let i = 0;i < 5;i++) {
let i = "abc";
setTimeout(()=>{
console.log(i);//abc,abc,abc,abc,abc
},1)
}
for(let i = 0;i < 5;i++) {
var i = "abc"; //Uncaught SyntaxError: Identifier 'i' has already been declared
setTimeout(()=>{
console.log(i);
},1)
}
for循环会形成两个作用域,for语句体作为父作用域,循环体会单独产生一个子作用域。
变量提升与暂时性死区
console.log(a); //undefined
var a = 10;
//console.log(b); //报错
let b = 10;
//console.log(c);//报错
const c = "NAME";
在js中,通过var和function声明的变量或函数,都会被提升至作用域顶部,也就是说(var声明的)变量可以先使用再声明。而ES6明确规定,如果区块中存在let命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。所以在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。
全局变量与全局对象属性
var a = 10;
console.log(a);//10
console.log(this.a);//10
console.log(window.a);//10
delete a;
console.log(a);//10
b = 20;
console.log(b);//20
console.log(this.b);//20
console.log(window.b);//20
delete b;
console.log(b);//Uncaught ReferenceError: b is not defined
let c = 30;
console.log(c);//30
console.log(this.c);//undefined
console.log(window.c);//undefined
delete c;
console.log(c);//30
①由var定义的全局变量在使用上等价于全局对象上的属性,只是configurable属性为false,所以不能通过delete删除。
②不通过关键字直接声明的变量是直接在全局对象上增加属性。
③使用let定义的变量与全局对象完全没有关系,也不能通过delete删除。
const常量
const a = 1;
a = 2; // // Uncaught TypeError: Assignment to constant variable
const b; // Uncaught SyntaxError: Missing initializer in const declaration
const 和 let 的作用域是一致的,不同的是 const 变量一旦被赋值,就不能再改变了,但是这并不意味着使用 const 声明的变量本身不可变,只是说它不可被再次赋值了,而且const 声明的变量必须经过初始化。
注意:const定义的复杂对象类型,保存的只是该对象的引用,其值还是可以被修改的。
总结
由上文我们可以知道,在开发中使用let和const是能提升我们代码的严谨性的,所以建议多使用let和const来替代var声明变量。