看书……摘抄
var关键字
- var声明作用域
使用var操作定义的变量会成为
包含它的函数的局部变量
,在函数内部定义一个变量,就意味着该变量将在函数退出时被销毁
。
(function test(){
var x='hello'
y='how are you?'// 全局变量y
})()
//y未使用var定义,全局可访问
console.log(y);//how are you?
//在函数外部打印x,x是函数内部的局部变量,外部无法访问
console.log(x);//x is not defined,控制台报错
- var声明提升
使用var关键字声明的变量会自动提升到
函数作用域顶部
。
// 执行函数不会报错,var 声明的变量提前,但是还没赋值
function foo(){
console.log(age);
var age=12;
/* 等价于
var age;
console.log(age);
age=12;
*/
}
foo()//undefined
let声明
let和var的作用差不多,但是二者最明显的区别是,
let
声明的范围是块作用域
,var
声明的范围是函数作用域
。
if(true){
let age=14
console.log(age);//14
}
console.log(age);//ReferenceError: age is not defined
- age变量之所以不能在if块外部被引用,是因为
let作用域仅限于该块内部
,块作用域是函数作用域的子集。var作用域也是如此。- 而且
let不允许同一个块作用域中出现冗余声明
,这样会导致报错。但是var可以。
- 暂时性死区
let和var的另一个重要的区别:就是let声明的变量
不会在作用域中被提升
。
// 暂时性死区
console.log(name);//undefined
var name='user'
console.log(age);//ReferenceError: Cannot access 'age' before initialization
let age=18
- 全局声明
let在
全局作用域中
声明的变量不会成为
window对象的属性,但是var声明的变量可以。
// 全局声明
var name='Maria'
console.log(window.name);//Maria
let age=19
console.log(window.age);//undefined
- 条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。
- for循环中的let声明
在let出现之前,for循环定义的迭代变量会
渗透到循环体外部
for(var i=0;i<5;i++){
// 逻辑……
}
console.log(i);//5
- 使用let之后:
for(let j=0;j<5;j++){
// 逻辑……
}
console.log(j);//ReferenceError: j is not defined
使用var的时候,最常见对迭代变量的奇特声明和修改:
for(var i=0;i<5;++i){
setTimeout(() => {
console.log(i);//5 5 5 5 5 var改成let的时候打印的就是0 1 2 3 4
}, 100);
}
原因:
- var声明的迭代变量: 在退出循环时,迭代变量保存的是导致循环退出的值:
5
。 在之后执行超时逻辑时,所有的i都是同一个变量
,最后输出的都是同一个最终值。- 使用let声明迭代变量: JavaScript在后台会为每个迭代循环
声明一个新的
迭代变量, 每一个settimeout引用的都是不同的变量实例,所以输出的就是循环执行过程中每个迭代变量的值。
const声明
- const的行为与let基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改const变量会导致运行时错误。
- const声明的限制
只适用于它指向的变量的引用
,如果const变量引用的是一个对象
,那么修改这个对象内部的属性
并不违反const的限制。
- const声明的number/string/null/undefined数据类型不可以再改变其值,但是对象可以改变。
- 非对象类型的不可以修改
const name='admin'
name='user'//Identifier 'name' has already been declared
//const声明的作用域也是块
const age=12
if(true){
const age=18
}
console.log(age);//12
for(const i=0;i<10;++i){
console.log(i);//结果是打印:0 并且报错 TypeError: Assignment to constant variable.
}
打印结果是0
,并且报错,在++i
的时候报错,非对象不可修改。
- 对象可以改变:
const obj={name:'这是一个对象'}
obj.name='对象可以修改内部属性'
console.log(obj);//对象可以修改内部属性
小结
最佳实践
- 不适用
var
- const优先,let次之。const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作,在
提前知道未来会有修改
时,再使用let。