var
、let
和const
很久不写JavaScript了, 对新的特性也不甚了解, 其实也不算新了, 看了一篇介绍定义变量的关键词的文章, 这里记录一下, 以便以后查阅.
在以前var
适用于所有场景, 唯一的对手是``, 也就是没有修饰符.
对于函数外的场景, 二者是一致的, 区别在于在函数内部.


var
的特性
-
全局作用域
var hello = 'hello' function world() { var abc = hello console.log(abc) } world() // hello
由于
hello
是全局的, 所以在world
方法中可以访问. -
函数级作用域
function world() { var abc = 'hello' console.log(abc) } world() // hello console.log(abc) // ReferenceError: abc is not defined
由于
abc
的作用域是函数内部, 所以在函数外部无法访问在函数内部通过var
声明的变量. -
可被重新声明
var abc = 'hello' var is_postive = true if (is_postive) { var abc = 'world' } console.log(abc) // world
-
可被重新赋值
var abc = 'hello' abc = 'world' console.log(abc) // world
-
变量提升
console.log(abc) // undefined var abc = 'hello'
实际上它是被解释成这样执行的:
var abc; console.log(abc); // abc未定义 abc = 'hello'
所以, 其实
abc
的声明是被提升到了最顶部, 但是赋值是undefined
.
let
的特性
-
全局作用域
let abc = 'hello' function hello() { console.log(abc) } hello() // hello
在代码块外部的
let
, 作用域范围和var
一样, 是全局的. -
块作用域
所谓块, 是指代码块. 具体就是在代码中被
{}
包起来的部分. 要区别于前面说的var
的函数级作用域.let is_postive = true if (is_postive) { let abc = 'hello' } console.log(abc) // ReferenceError: abc is not defined
注意这里和前面的变量提升部分的区别, 变量被提升后, 因为已经“声明”, 所以不会报错, 只是值变成了
undefined
, 而这里是纯粹的没有声明, 所以会报一个引用错误.let abc = 'hello' let is_postive = true if (is_postive) { let abc = 'world' console.log(abc) // world } console.log(abc) // hello
从这里可以看出, 全局的
abc
和代码块中的abc
是互不影响的. -
不可被重新声明
为了解决
var
声明的变量可以被重复声明的问题, 才引入了let
, 所以let abc = 'hello' let abc = 'world' // SyntaxError: redeclaration of let abc
-
可被重新赋值
这个特性其实是区别于
const
let abc = 'hello' abc = 'world' console.log(abc) // world
-
变量提升
变量提升到顶部和
var
相同, 但它并没有被赋值undefined
, 其实它并没有被初始化, 所以console.log(abc) let abc = 'hello' // ReferenceError: can't access lexical declaration `abc' before initialization
值得一提的是, 只有在上下文存在对
abc
的let
形式的赋值时, 才会报上述错误, 如果仅仅是console.log(cde)
这种, 其实和在其下面使用var
声明变量效果一样.
const
的特性
-
全局作用域
同
var
和let
-
块作用域
同
let
-
不可被重新声明
其实可以理解成PHP中的
const
(常量), 声明和赋值必须在同一条语句, 一旦完成, 就不可改变(限作用域内).const abc = 'hello' const abc = 'world' //SyntaxError: redeclaration of const abc note: Previously declared at line 1, column 6
前提是在相同作用域内
const abc = 'hello' if (true) { const abc = 'world' console.log(abc) // world } console.log(abc) // hello
-
不可被重新赋值
const abc = 'hello' abc = 'world' // TypeError: invalid assignment to const `abc'
但如果用
const
声明的变量是对象时const abc = {'k1': 'v1', 'k2': 'v2'} console.log(abc) //Object { k1: "v1", k2: "v2" } abc.k1 = 'v3' console.log(abc) //Object { k1: "v3", k2: "v2" }
当然, 这种情况下重新给变量整体赋值还是不允许的
-
变量提升
同
let
总结
关键词 | 全局作用域 | 函数作用域 | 块作用域 | 重新声明 | 重新赋值 |
---|---|---|---|---|---|
var |
YES | YES | NO | YES | YES |
let |
YES | NO | YES | NO | YES |
const |
YES | NO | YES | NO | NO |