欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS中的var、let、const三者的区别

程序员文章站 2022-07-14 10:01:34
...

ES5:var ES6:let、const
ES5中的作用域有—全局作用域、函数作用域
ES6中新增了—块级作用域(块级作用域由{}包裹,if语句、for语句中的{}也属于块级作用域)

1. var

  • 没有块级作用域的概念
//Global Scope
{
  var a = 10;
}
console.log(a);  //10`
//上面代码中,在Global Scope(全局作用域)中,且在Block Scope(块级作用域){}中,
//a输出结果为10,由此可以看出var声明的变量不存在block scope的概念;
  • 有全局作用域、函数作用域的概念
//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报错了。
  • 不初始化值默认为undefined
//Global Scope
var a;
console.log(a);  //undefined
//上面代码中,在Global Scope中用var声明了a,但没有初始化值,它的值默认为undefined,这里是undefined是undefined类型,而不是字符串。
  • 存在变量提升
//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,自己去看作用域链。
  • 全局作用域用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()是等价的。
  • 同一作用域中允许重复声明
//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也是一样的。

2. let

  • 有块级作用域的概念
{
 //Block Scope
 let a = 10;
}
console.log(a);  //ReferenceError: a is not defined
//上面代码中,打印a报错,说明存在Block Scope的概念。
  • 不存在变量提升
{
//Block Scope
console.log(a);  //ReferenceError: Cannot access 'a' before initialization
let a = 10;
}
//上面代码中,打印a报错:无法在初始化之前访问。说明不存在变量提升。
  • 暂时性死区
{
  //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声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时死区。

//简单的来说:使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

//其实上面不存在变量提升的例子中,其实也是暂时性死区,因为它有暂时性死区的概念,所以它压根就不存在变量提升了。
  • 不存在全局作用域的概念
<script>
var foo = 'foo';
function bar(){}
let a = 10;
console.log(a);  //10
console.log(window.a);  //undefined
</script>

JS中的var、let、const三者的区别
上面代码中,打印变量a为10,但是打印window.a为undefined,说明它不会挂在到window对象下,其实window对象是个顶层对象,他与Global不是一个东西,只不过在ES5中设计的时候,就把在Global中声明的变量(全局变量)自动的挂载到了window这个顶层对象里面了,所以我们在使用var声明全局变量的时候会自动把这个变量挂载到window对象里去。window对象与Global会互相挂钩。

图例-1是在Firefox Developer Edition中的Debugger显示的。

  • 同一块作用域中不允许重复声明
{
  //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
}

3. const

  • 与let特性一样,仅有2个差别
  • 区别1——必须立即初始化,不能留到以后赋值
{ 
//Block Scope 
const a; 
//SyntaxError: Missing initializer in const declaration 
}
//上面代码中,用`const`声明的变量`a`没有进行初始化,所以报错。
  • 区别2——常量的值不能改变
//Block Scope 
const a = 10; 
a = 20; //TypeError: Assignment to constant variable 
//上面代码中,用`const`声明了变量`a`且初始化为10,然后试图修改`a`的值,报错。
// `const`实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
 
相关标签: js javascript