var let const
var,let 都是 javascript 中定义变量的方式。
const 则用来定义常量。
var
适用于 ECMAScript 的所有版本。
声明作用域
var 的声明作用域是函数作用域或全局作用域
function test(){
var message = 'hi'; // message 仅在函数作用域中有效,函数执行完后会自动销毁
}
test();
console.log(message); // ReferenceError: message is not defined
如果此处不使用 var,message 则会被定义为全局变量(不推荐使用)
function test(){
message = 'hi'; // 相当于在全局定义了 window.message = 'hi'
}
test();
console.log(message); // hi
变量提升(声明提升)
使用 var 声明的变量会自动提升到函数作用域的顶部
function foo(){
console.log(age);
var age = 26;
}
foo(); // undefined
以上代码等价于
function foo(){
var age; // 变量提升或者说是预加载,将 age 的定义提前了
console.log(age);
age = 26;
}
foo(); // undefined
重复声明
function foo(){
var age = 16;
var age = 26;
var age = 36;
console.log(age);
}
foo(); // 36
也可以看做
function foo(){
var age;
age = 16;
age = 26;
age = 36;
console.log(age);
}
foo(); // 36
全局声明
var 在全局环境定义的变量会被挂到 window 上。
var name = 'Matt'; // 相当于 window.name = 'Matt'
console.log(window.name); // Matt
let
let 和 var 一样,也是用来定义变量。
ES 2015(ES6)版本及以后才能使用 let 声明。
声明作用域
let 是块作用域,var 是函数作用域。
if(true){
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt
因为 var 是函数作用域,不受块的局限,所以在外面也能拿到 name。
if(true){
let name = 'Matt';
console.log(name); // Matt
}
console.log(name); // ReferenceError: name is not defined
而 let 是块作用域,所以 name 在 if 块中定义,外部不能使用到 name。
暂时性死区(相反于变量提升)
在 let 中,没有变量提升,即不能在定义前使用。所以在 let 声明之前的瞬间称为 “暂时性死区”(temporal dead zone),在此阶段对变量的调用都会抛出 ReferenceError。
console.log(name); // undefined
var name = 'Matt';
console.log(age); // ReferenceError: age is not defined
let age = 26;
同块作用域不允许重复声明
在 var 声明变量时,由于声明会被提升,javascript 引擎会自动将多余的声明在作用域顶部合并为一个声明。
var name = 'Matt';
let age = 26;
var name = 'Nicholas';
let age = 36; // SyntaxError: Identifier 'age' has already been declared
同样的
<script>
var name = 'Matt';
let age = 26;
</script>
<script>
var name = 'Nicholas';
let age = 36; // SyntaxError: Identifier 'age' has already been declared
</script>
var 和 let 的区别
- 作用范围,var 的作用范围是函数作用域,let 的作用范围是块。
- var 有变量提升,let 没有(暂时性死区)。
- var 可以重复声明,let 不能重复声明。
- var 在全局定义会挂在 window 上,let 则不会。
- var 在所有 javascript 版本都可以使用,let 需要 es6 及以后。
const
const 的行为和 let 基本相同。
区别在于 const 用来定义常量,初始化时必须赋值,且后续不能修改。
const name; // SyntaxError: Missing initializer in const declaration
const age = 26;
age = 36; // TypeError: Assignment to constant variable
const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量指向一个对象,修改对象内部的属性不违法 const 的限制,同样数组也是。
const obj = { name: 'Matt' };
obj.name = 'Nicholas';
console.log(obj.name); // Nicholas
const arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
IIFE
可以通过 IIFE 将 var 改造为块级作用域。
if(true){
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt
if(true){
(function(){
var name = 'Matt';
console.log(name); // Matt
})();
}
console.log(name); // ReferenceError: name is not defined
可以观察到 webpack 打包后的 javascript 代码就是这种表现形式,来保证兼容性。
例子🌰:
1.
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
2.
for(var i = 0; i < 5; ++i){
setTimeout(() => console.log(i), 0);
}
// 结果 5,5,5,5,5
for(let i = 0; i < 5; ++i){
setTimeout(() => console.log(i), 0);
}
// 结果 0,1,2,3,4
引用
- 《JavaScript 高级程序设计(第四版)》
- 《现代 JavaScript 教程》
结语
如果有错误,欢迎大佬指正。