ECMAScript 中有3个关键字可以声明变量,var,const 和let。其中,var 在ECMAScript 的所有版本中都可以使用,而const 和let 只能在ECMAScript6 及更晚的版本中使用。
var 关键字
(1)var 声明作用域
在函数外声明的变量的作用域是全局作用域。全局都可以访问。
var message = "test";
function test() {
console.log(message);
}
test();//test
console.log(message);//test
在函数内部声明的变量的作用域是函数作用域。只能在函数内部访问。
function test() {
var message = "test";
console.log(message); //test
}
test();
console.log(message); // process.html:16 Uncaught ReferenceError: message is not defined
在函数内部省略var 关键字声明的变量的作用域是全局作用域。全局都可以访问。
function test() {
message = "test";
console.log(message);
}
test();
console.log(message); //test
(2)var 作用域提升
使用var 关键字声明的变量会自动提升到函数作用域的顶部,这个过程叫作用域的提升。
function foo() {
console.log(message);
var message = "hello world";
}
foo(); // undefined
不报错的原因是ECMADScript 运行时会把他看成等加于如下的代码
function foo() {
var message;
console.log(message);
message = "hello world";
}
foo(); // undefined
反复多次声明同一个变量也没有问题
function foo() {
var age = 16;
var age = 36;
var age = 26;
console.log(age);
}
foo(); //26
let 关键字 与var 关键字的区别
区别一:
let 关键字与var 关键字最明显的区别是,let 声明的范围是 块作用域,而var 声明的范围是函数作用域。
if (true) {
var name = "wang";
console.log(name);
}
console.log(name);
if (true) {
let age = 26;
console.log(age);
}
console.log(age);
name 是使用var 声明的所以在该段代码的整个作用域中都可用,该段代码可能在全局作用域中,或者在函数作用域中。age 是使用let 关键字声明的变量,作用域是块级作用域,出了{},就不能再访问。
区别2:
let 关键字不允许在同一作用域中存在重复声明,也不允许在同一作用域中有与var 关键字同名的变量。但是var 关键字允许。
var name;
var name;
let name;
let name;//Uncaught SyntaxError: Identifier 'name' has already been declared
var name;
let name;//Uncaught SyntaxError: Identifier 'name' has already been declared
区别3:暂时性死区
let 关键字声明的变量不会在作用域中被提升。
console.log(name);//undefined 存在作用域提升
var name = 'Matt'
conslog.log(age);//ReferenceError: age没有定义 ,没有作用域提升。
let age = 36;
在解析代码时,JavaScript 引擎也会注意出现在块后面的let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在let 声明前的执行瞬间被称为“暂时性死区“,在此阶段引用任何后面才声明的变量都会抛出ReferenceError。
区别4:全局作用域
与var关键字不同,使用let 在全局作用域中声明的变量不会成为window对象的属性,而var 关键字声明的变量则会成为window 的对象的属性。
var name = "wang";
console.log(name); // wang
console.log(window.name); // wang
let age = 26;
console.log(age); // undefined
区别5: for 循环中的let
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
在退出循环时,var 关键字中迭代变量保存的是导致循环退出的值:5.在之后执行超时循环时,所有的i都是同一个变量,因而输出的都是同一个最终值。
而使用let 声明迭代变量时,JavaScript 引擎后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例,所以console.log输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。
const 声明
const 的行为与let 基本相同,唯一一个重要的区别是用它声明的变量必须同时初始化变量,且尝试修改const 声明的变量会导致运行时错误。
const age = 26;
age = 36;//TypeError:给常量赋值。
const 也不允许重复声明
const name = "wang"
const name = "li"
const 声明的作用域也是块
const name = "wang"
if(true){
const name = 'li'
}
console.log(name);//wang
const 声明的限制只适用于它指向的变量的引用。换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。
const person = {}
person.name = "wang" // ok
声明变量的最佳实践
1.不使用用var
2.const 优先,let 次之