0%

js变量声明

声明变量:var,const,let

var声明:

使用var操作符定义的变量会成为包含它的函数的局部变量,如:使用var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:

1
2
3
4
5
function test() { 
var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!

这里,message 变量是在函数内部使用 var 定义的。函数叫 test(),调用它会创建这个变量并给
它赋值。调用之后变量随即被销毁,因此示例中的最后一行会导致错误。不过,在函数内定义变量时省
略 var 操作符,可以创建一个全局变量:

1
2
3
4
5
function test() { 
message = "hi"; // 全局变量
}
test();
console.log(message); // "hi"

去掉之前的 var 操作符之后,message 就变成了全局变量。只要调用一次函数 test(),就会定义
这个变量,并且可以在函数外部访问到。

var声明提升:

使用var时,下面代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部:

1
2
3
4
5
function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined

上述代码等同于:

1
2
3
4
5
6
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined

let声明:

let声明和var声明的作用差不多,但有着非常重要的区别。最明显的区别就是,let声明的范围是作用域,而var声明的范围是函数作用域。

例如:

1
2
3
4
5
6
7
8
9
10
if (true) { 
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt
if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义

在这里,age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let。

let不允许同一个块作用域中出现冗余声明。这样会导致报错。

1
2
let age; 
let age; // SyntaxError;标识符 age 已经声明过了

对声明冗余报错不会因混用 let 和 var 而受影响。这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在。

1
2
3
4
var name; 
let name; // SyntaxError
let age;
var age; // SyntaxError

暂时性死区:

let不会在作用中被提升

1
2
3
4
5
6
7
// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;

在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。

全局变量:

与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声
明的变量则会)。

1
2
3
4
var name = 'Matt'; 
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined

不过,let 声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免 SyntaxError,必须确保页面不会重复声明同一个变量。

条件声明:

在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。

为此,对于 let 这个新的 ES6 声明关键字,不能依赖条件声明模式。

const声明:

const声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误, const 也不允许重复声明,const 声明的作用域也是块。

如:

1
2
3
4
5
6
7
8
9
10
11
const age = 26;
age = 36; // TypeError: 给常量赋值
// const 也不允许重复声明
const name = 'Matt';
const name = 'Nicholas'; // SyntaxError
// const 声明的作用域也是块
const name = 'Matt';
if (true) {
const name = 'Nicholas';
}
console.log(name); // Matt

const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象,
那么修改这个对象内部的属性并不违反 const 的限制。

1
2
const person = {}; 
person.name = 'Matt'; // ok

JavaScript 引擎会为 for 循环中的 let 声明分别创建独立的变量实例,虽然 const 变量跟 let 变量很相似,但是不能用 const 来声明迭代变量(因为迭代变量会自增):

1
for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值