玩转JS基础——声明变量关键字汇总

简介: 在 JavaScript*中,一共存在 3 种声明变量的方式

声明变量关键字汇总

在 JavaScript 中,一共存在 3 种声明变量的方式:

  • var
  • let
  • const

之所以有 3 种方式,这是由于历史原因造成的。最初声明变量的关键字就是 var,但是为了解决作用域的问题,所以后面新增了 let 和 const 的方式。

作用域

首先我们来了解一下作用域。

ES5 中的作用域有:全局作用域、函数作用域,ES6 中新增了块级作用域。块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域。

关于作用域的更多内容,可以参阅《作用域和作用域链》章节。

var 关键字

  1. 没有块级作用域的概念
//Global Scope
{
  var a = 10;
}
console.log(a);  //10

上面代码中,在 Global Scope(全局作用域)中,且在 Block Scope(块级作用域) { } 中,a 输出结果为 10,由此可以看出 var 声明的变量不存在 Block Scope 的概念

  1. 有全局作用域、函数作用域的概念
//Global Scope
var a = 10;
function checkscope(){
    //Local Scope
    var b = 20;
    console.log(a);  //10
    console.log(b);  //20
}
checkscope();
console.log(b);  //ReferenceError: b is not defined

上面代码中,在 Global Scope 中用 var 声明了 a,在 checkscope 函数中的 Local Scope(本地作用域、函数作用域)中打印出了 10,但是在 Global Scope 中打印的变量 b 报错了。

  1. 不初始化值默认为 undefined
//Global Scope
var a;
console.log(a);  //undefined

上面代码中,在 Global Scope 中用 var 声明了 a,但没有初始化值,它的值默认为 undefined,这里是 undefined 是 undefined 类型,而不是字符串。

  1. 存在变量提升
//Global Scope
console.log(a);  //undefined
var a = 10;

checkscope();
function checkscope(){
    //Local Scope
    console.log(a);  //undefined
    var a;
}

上面代码中,先打印了 a,然后用 var 声明变量 a。变量提升是因为 js 需要经历编译和执行阶段。而 js 在编译阶段的时候,会搜集所有的变量声明并且提前声明变量。

可以将这个过程形象地想象成所有的声明(变量)都会被“移动”到各自作用域的最顶端,这个过程被称为提升。

至于 checkscope 函数中的变量 a 为什么输出 undefined,可以参阅《作用域和作用域链》章节。

  1. 全局作用域用 var 声明的变量会挂载到 window 对象下
//Global Scope
var a = 10;
console.log(a);  //10
console.log(window.a);  //10
console.log(this.a);  //10

上面代码中,打印出了 3 个 10,访问 a 和 window.a 或是 this.a 都是等价的。

举个例子:比如我要访问 location 对象,使用 location 可以访问,使用 window.location 也可以访问,只不过 window 对象可以省略不写,就像 new Array( )  和 new window.Array( )  是等价的。

  1. 同一作用域中允许重复声明
//Global Scope
var a = 10;
var a = 20;
console.log(a);  //20

checkscope();
function checkscope(){
    //Local Scope
    var b = 10;
    var b = 20;
    console.log(b);  //20
}

上面代码中,在 Global Scope 中声明了 2 次 a,以最后一次声明有效,打印为 20。同理,在 Local Scope 也是一样的。

let 关键字

  1. 有块级作用域的概念
{
   //Block Scope
   let a = 10;
}
console.log(a);  //ReferenceError: a is not defined

上面代码中,打印 a 报错,说明存在 Block Scope 的概念。

  1. 不存在变量提升
{
  //Block Scope
  console.log(a);  //ReferenceError: Cannot access 'a' before initialization
  let a = 10;
}

上面代码中,打印 a 报错:无法在初始化之前访问。说明不存在变量提升。

  1. 暂时性死区
{
  //Block Scope
  console.log(a);  //ReferenceError: Cannot access 'a' before initialization
  let a = 20;
}

if (true) {
  //TDZ开始
  console.log(a);  //ReferenceError: Cannot access 'a' before initialization

  let a; //TDZ结束
  console.log(a);  //undefined

  a = 123;
  console.log(a);  //123
}

上面代码中,使用 let 声明的变量 a,导致绑定这个块级作用域,所以在 let 声明变量前,打印的变量 a 报错。

这是因为使用 let/const 所声明的变量会存在暂时性死区。

什么叫做暂时性死区域呢?

ES6 标准中对 let/const 声明中的解释 第13章,有如下一段文字:

The variables are created when their containing Lexical Environment is instantiated but may not be accessed inany way until the variable’s LexicalBinding is evaluated.

翻译成人话就是:

当程序的控制流程在新的作用域( module、function 或  block 作用域)进行实例化时,在此作用域中用  let/const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时死区。

再简单理解就是:

ES6 规定, let/const 命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。\
总之,在代码块内,使用  let/const 命令声明变量之前,该变量都是不可用的。\
这在语法上,称为  “暂时性死区” (  temporal dead zone,简称  TDZ)。

其实上面不存在变量提升的例子中,其实也是暂时性死区,因为它有暂时性死区的概念,所以它压根就不存在变量提升了。

  1. 同一块作用域中不允许重复声明
{
  //Block Scope
  let A;
  var A;  //SyntaxError: Identifier 'A' has already been declared
}
{
  //Block Scope
  var A;
  let A;  //SyntaxError: Identifier 'A' has already been declared
}
{
  //Block Scope
  let A;
  let A;  //SyntaxError: Identifier 'A' has already been declared
}

const 关键字

  1. 必须立即初始化,不能留到以后赋值
// Block Scope 
const a; // SyntaxError: Missing initializer in const declaration } 

上面代码中,用 const 声明的变量 a 没有进行初始化,所以报错。

  1. 常量的值不能改变
//Block Scope 
{
  const a = 10; 
    a = 20; // TypeError: Assignment to constant variable
}

上面代码中,用 const 声明了变量 a 且初始化为 10,然后试图修改 a 的值,报错。

const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。

特点总结

  • var 关键字
  1. 没有块级作用域的概念
  2. 有全局作用域、函数作用域的概念
  3. 不初始化值默认为 undefined
  4. 存在变量提升
  5. 全局作用域用 var 声明的变量会挂载到 window 对象下
  6. 同一作用域中允许重复声明
  • let 关键字
  1. 有块级作用域的概念
  2. 不存在变量提升
  3. 暂时性死区
  4. 同一块作用域中不允许重复声明
  • const 关键字
  1. 与 let 特性一样,仅有 2 个差别
  2. 区别 1:必须立即初始化,不能留到以后赋值
  3. 区别 2:常量的值不能改变
相关文章
|
23天前
|
JavaScript
变量和函数提升(js的问题)
变量和函数提升(js的问题)
|
25天前
|
JavaScript 前端开发
JavaScript 中如何检测一个变量是一个 String 类型?
JavaScript 中如何检测一个变量是一个 String 类型?
21 2
|
3月前
|
JavaScript 前端开发 Java
JavaScript基础语法(变量)
JavaScript基础语法(变量)
48 0
|
4月前
|
中间件
在 Egg.js 应用中,你可以通过 `this` 关键字来获取上下文
在 Egg.js 应用中,你可以通过 `this` 关键字来获取上下文
39 1
|
3天前
|
JavaScript 前端开发
js开发:请解释this关键字在JavaScript中的用法。
【4月更文挑战第23天】JavaScript的this关键字根据执行环境指向不同对象:全局中指向全局对象(如window),普通函数中默认指向全局对象,作为方法调用时指向调用对象;构造函数中指向新实例,箭头函数继承所在上下文的this。可通过call、apply、bind方法显式改变this指向。
7 1
|
1月前
|
JavaScript 前端开发 开发者
js开发:请解释什么是ES6的let和const关键字,以及它们与var关键字的区别。
ES6引入`let`和`const`替代`var`声明变量。`let`有块级作用域,存在暂时性死区,不进行变量提升,可重新赋值。`const`用于常量,值不可变但引用类型内容可变,同样有块级作用域和暂时性死区。与`var`主要区别在于作用域、变量提升和可变性。这些改进提高了代码的可预测性和安全性。
24 2
|
1月前
|
JavaScript 前端开发 算法
JavaScript 关键字 debugger 的作用和使用场景介绍
JavaScript 关键字 debugger 的作用和使用场景介绍
35 0
|
1月前
|
JavaScript 前端开发 容器
javascript中的变量定义
javascript中的变量定义
|
1月前
|
JavaScript 前端开发 编译器
编程笔记 html5&css&js 077 Javascript 关键字
编程笔记 html5&css&js 077 Javascript 关键字
|
1月前
|
存储 JavaScript 前端开发
编程笔记 html5&css&js 075 Javascript 常量和变量
编程笔记 html5&css&js 075 Javascript 常量和变量