所谓变量,你可以把它理解成一个箱子,我们可以向箱子里面放入一些值,方便后面使用。
之所以称之为变量,就是因为这个箱子里面的值是可以改变的,后放入的值会覆盖前面的值。
而所谓常量,与变量是相对的,只能是只能赋值一次,一旦被初始化后,就不能再修改的箱子。
本文将介绍 JavaScript 中的变量和常量。
- 声明变量
- let 关键字
- 变量提升
- 声明常量
- 声明规则最佳实践
声明变量
要声明一个变量,可以使用 var 关键字。例如:
var name;
在上面的代码中,我们声明了一个名为 name 的变量。目前我们还没有对变量进行赋值,所有该变量默认的值为 undefined。
在有了变量后,我们就可以对这个变量进行赋值了,例如:
var name = "xiejie";
在上面的代码中,我们声明了一个名为 name 的变量后,给这个变量赋值 xiejie。
我们把对变量的第一次赋值称之为变量的初始化。
由于 JavaScript 是一门动态语言,所以变量也是松散类型的。这意味着变量可以保存任何类型的数据。例如:
var name = "xiejie";
name = 100; // 合法,但是不推荐
在上面的语句中,我们先对 name 变量赋值了一个字符串类型的值,之后又重新赋值为数字类型 100,虽然这从语法层面来讲是合法的,但是不推荐改变变量保存值的类型。
var 作为 JavaScript 中最原始的声明变量方式,残存着许多奇怪的特性。
例如,如果是使用 var 关键字声明变量时,允许重复声明。
重复声明如果不带有赋值操作,JavaScript 引擎会自动忽略后面的变量声明:
var test = 3;
var test; // 这一次声明会被忽略
console.log(test); // 3
重新声明如果带有赋值操作,那么会进行数据覆盖:
var test = 3;
var test = 5; // 这一次声明带有赋值,会覆盖上面的值
console.log(test); // 5
如果试图读取一个没有声明的变量的值,JavaScript 引擎会报错:
console.log(a); // 报错,因为没有声明变量 a
但是 JavaScript 引擎允许遗漏声明,即直接对一个没有声明的变量进行赋值,该操作会自动声明变量:
a = 5;
console.log(a); // 5
在上面的代码中,我们并没有声明变量 a,而是直接对变量 a 进行赋值。
此时 JavaScript 引擎会自动声明该变量。
var 关键字所声明的变量,还有一个很大的特点,那就是不具备局部作用域。
这里需要先解释一下什么是作用域。
所谓作用域,指的是变量在程序中能够被访问的有效范围。而局部作用域,则表示某个区域内的变量只在该区域内有效,出了这个区域后便无法被访问使用。
例如:
{
var name = "xiejie";
}
console.log(name); // xiejie
在上面的代码中,我们在声明变量语句的前后添加了一对大括号,如果是类似于 C 语言这样的强类型语言,大括号则代表了一个局部作用域,name 只在这对大括号内生效。
然而由于 var 关键字声明的变量不具备局部作用域,所以我们可以看到在大括号外,我们也能访问到这个 name 变量的值。
let 关键字
这因为 var 关键字声明的变量有诸多奇怪的特性,所以从 ES6 开始引入了新的变量声明关键字 let。
使用 let 来声明变量,上述的奇怪特性就都被解决了。
例如,无法重复声明变量:
let test = 3;
let test; // 报错,test 变量已经存在
let 关键字所声明的变量也有了局部作用域,例如:
{
let name = "xiejie"; // 该变量只在大括号内有效
}
console.log(name); // 报错,name 没有被定义
变量提升
var 和 let 声明的变量,还有一个重要的区别就是变量提升。
这里首先需要解释一下什么是变量提升。例如下面的代码:
console.log(name); // undefined
var name = "xiejie";
console.log(name); // xiejie
在上面的代码中,打印出来的结果分别为 undefined 和 xiejie,究其原因,是因为使用 var 所声明的变量,声明部分会被提升到该作用域的最顶部,形成类似于如下的代码:
var name; // 声明被提升到了该作用域的最顶部
console.log(name); // undefined
name = "xiejie";
console.log(name); // xiejie
而 let 所声明的变量,则没有变量提升的现象。
console.log(name); // 报错,无法访问 name 在初始化之前
let name = "xiejie";
这是由于 let 所声明的变量,存在暂时性死区(temporal dead zone)。
所谓暂时性死区,指的是只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
声明常量
ES6 除了带来 let 关键字以外,还推出了全新的 const 关键字来声明一个常量。
const 关键字的特点在于,用它声明常量时必须同时初始化该常量,并且该值一旦被初始化后,就不能再修改了。例如:
const name; // 报错,const 声明缺少初始化值
name = "xiejie";
console.log(name);
在上面的代码中,我们使用 const 关键字声明了一个常量,但是没有进行初始化,所以报错。
const name = "xiejie";
name = "jiexie"; // 报错,无法修改常量的值
console.log(name);
在上面的代码中,我们尝试修改一个常量值,所以报错。
和 let 一样,使用 const 所声明的变量,同样存在局部作用域。例如:
{
const name = "xiejie";
}
console.log(name); // 报错,name 没有定义
在上面的代码中,我们在大括号里面使用 const 声明了一个 name 常量,该常量的有效范围只在大括号以内,外部无法进行访问。
声明规则最佳实践
ES6 新增的 let 和 const 关键字,从客观上来看为这门语言在声明作用域和语义上提供了更好的支持。行为怪异的 var 所造成的各种问题,已经让 JavaScript 社区为之苦恼了很多年。随着这两个新关键字的出现,新的有助于提升代码质量的最佳实践也逐渐显现。
- 不使用 var
有了 let 和 const,大多数开发者会发现自己不再需要 var 了。限制自己只使用 let 和 const 有助于提升代码质量,因为变量有了明确的作用域,声明位置,以及不变的值。 - const 优先,let 次之
使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发人员认为应该优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。这样可以让开发者更有信息地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。
总结
在 JavaScript 中声明变量的方式有 3 种:var、let 以及 const。其中 var 现在已经不推荐使用了。
var 关键字声明的值不存在局部作用域,而 let 和 const 声明的值存在局部作用域。
var 声明的变量存在变量提升现象,而 let 声明的变量则没有变量提升现象。这是由于 let 所声明的变量,存在暂时性死区(temporal dead zone)。
-EOF-