所谓变量,你可以把它理解成一个箱子,我们可以向箱子里面放入一些值,方便后面使用。

之所以称之为变量,就是因为这个箱子里面的值是可以改变的,后放入的值会覆盖前面的值。

而所谓常量,与变量是相对的,只能是只能赋值一次,一旦被初始化后,就不能再修改的箱子。

本文将介绍 JavaScript 中的变量和常量。

  • 声明变量
  • let 关键字
  • 变量提升
  • 声明常量
  • 声明规则最佳实践

声明变量

要声明一个变量,可以使用 var 关键字。例如:

  1. var name;

在上面的代码中,我们声明了一个名为 name 的变量。目前我们还没有对变量进行赋值,所有该变量默认的值为 undefined

在有了变量后,我们就可以对这个变量进行赋值了,例如:

  1. var name = "xiejie";

在上面的代码中,我们声明了一个名为 name 的变量后,给这个变量赋值 xiejie

我们把对变量的第一次赋值称之为变量的初始化

由于 JavaScript 是一门动态语言,所以变量也是松散类型的。这意味着变量可以保存任何类型的数据。例如:

  1. var name = "xiejie";
  2. name = 100; // 合法,但是不推荐

在上面的语句中,我们先对 name 变量赋值了一个字符串类型的值,之后又重新赋值为数字类型 100,虽然这从语法层面来讲是合法的,但是不推荐改变变量保存值的类型

var 作为 JavaScript 中最原始的声明变量方式,残存着许多奇怪的特性。

例如,如果是使用 var 关键字声明变量时,允许重复声明。

重复声明如果不带有赋值操作,JavaScript 引擎会自动忽略后面的变量声明:

  1. var test = 3;
  2. var test; // 这一次声明会被忽略
  3. console.log(test); // 3

重新声明如果带有赋值操作,那么会进行数据覆盖:

  1. var test = 3;
  2. var test = 5; // 这一次声明带有赋值,会覆盖上面的值
  3. console.log(test); // 5

如果试图读取一个没有声明的变量的值,JavaScript 引擎会报错:

  1. console.log(a); // 报错,因为没有声明变量 a

但是 JavaScript 引擎允许遗漏声明,即直接对一个没有声明的变量进行赋值,该操作会自动声明变量:

  1. a = 5;
  2. console.log(a); // 5

在上面的代码中,我们并没有声明变量 a,而是直接对变量 a 进行赋值。

此时 JavaScript 引擎会自动声明该变量。

var 关键字所声明的变量,还有一个很大的特点,那就是不具备局部作用域。

这里需要先解释一下什么是作用域。

所谓作用域,指的是变量在程序中能够被访问的有效范围。而局部作用域,则表示某个区域内的变量只在该区域内有效,出了这个区域后便无法被访问使用。

例如:

  1. {
  2. var name = "xiejie";
  3. }
  4. console.log(name); // xiejie

在上面的代码中,我们在声明变量语句的前后添加了一对大括号,如果是类似于 C 语言这样的强类型语言,大括号则代表了一个局部作用域,name 只在这对大括号内生效。

然而由于 var 关键字声明的变量不具备局部作用域,所以我们可以看到在大括号外,我们也能访问到这个 name 变量的值。

let 关键字

这因为 var 关键字声明的变量有诸多奇怪的特性,所以从 ES6 开始引入了新的变量声明关键字 let

使用 let 来声明变量,上述的奇怪特性就都被解决了。

例如,无法重复声明变量:

  1. let test = 3;
  2. let test; // 报错,test 变量已经存在

let 关键字所声明的变量也有了局部作用域,例如:

  1. {
  2. let name = "xiejie"; // 该变量只在大括号内有效
  3. }
  4. console.log(name); // 报错,name 没有被定义

变量提升

varlet 声明的变量,还有一个重要的区别就是变量提升

这里首先需要解释一下什么是变量提升。例如下面的代码:

  1. console.log(name); // undefined
  2. var name = "xiejie";
  3. console.log(name); // xiejie

在上面的代码中,打印出来的结果分别为 undefinedxiejie,究其原因,是因为使用 var 所声明的变量,声明部分会被提升到该作用域的最顶部,形成类似于如下的代码:

  1. var name; // 声明被提升到了该作用域的最顶部
  2. console.log(name); // undefined
  3. name = "xiejie";
  4. console.log(name); // xiejie

let 所声明的变量,则没有变量提升的现象。

  1. console.log(name); // 报错,无法访问 name 在初始化之前
  2. let name = "xiejie";

这是由于 let 所声明的变量,存在暂时性死区(temporal dead zone)。

所谓暂时性死区,指的是只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

声明常量

ES6 除了带来 let 关键字以外,还推出了全新的 const 关键字来声明一个常量。

const 关键字的特点在于,用它声明常量时必须同时初始化该常量,并且该值一旦被初始化后,就不能再修改了。例如:

  1. const name; // 报错,const 声明缺少初始化值
  2. name = "xiejie";
  3. console.log(name);

在上面的代码中,我们使用 const 关键字声明了一个常量,但是没有进行初始化,所以报错。

  1. const name = "xiejie";
  2. name = "jiexie"; // 报错,无法修改常量的值
  3. console.log(name);

在上面的代码中,我们尝试修改一个常量值,所以报错。

let 一样,使用 const 所声明的变量,同样存在局部作用域。例如:

  1. {
  2. const name = "xiejie";
  3. }
  4. console.log(name); // 报错,name 没有定义

在上面的代码中,我们在大括号里面使用 const 声明了一个 name 常量,该常量的有效范围只在大括号以内,外部无法进行访问。

声明规则最佳实践

ES6 新增的 letconst 关键字,从客观上来看为这门语言在声明作用域和语义上提供了更好的支持。行为怪异的 var 所造成的各种问题,已经让 JavaScript 社区为之苦恼了很多年。随着这两个新关键字的出现,新的有助于提升代码质量的最佳实践也逐渐显现。

  1. 不使用 var
    有了 letconst,大多数开发者会发现自己不再需要 var 了。限制自己只使用 letconst 有助于提升代码质量,因为变量有了明确的作用域,声明位置,以及不变的值。
  2. const 优先,let 次之
    使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发人员认为应该优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。这样可以让开发者更有信息地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。

总结

  1. JavaScript 中声明变量的方式有 3 种:var、let 以及 const。其中 var 现在已经不推荐使用了。

  2. var 关键字声明的值不存在局部作用域,而 letconst 声明的值存在局部作用域。

  3. var 声明的变量存在变量提升现象,而 let 声明的变量则没有变量提升现象。这是由于 let 所声明的变量,存在暂时性死区(temporal dead zone)。

-EOF-