JavaScript 的var、let 与const

更新日期: 2022-06-14阅读: 685标签: 变量

JavaScript 因为历史悠久, 所以你可能会遇到经过多人更改过的JavaScript 程式, 里面混杂了不同时期JavaScript 的语法, 导致有时候JavaScript 程式就是难懂, 本文将针对宣告变数的几种方法加以说明, 期望能让大家快速理解其中的差别。

使用var 宣告函式层级的变数

过去最常看到的变数宣告方是就是使用 , 它宣告的变数是函式层级, 也就是只要离开宣告时所在的函式, 这个变数就失效了, 例如: var

function  foo ()  {
  var a = 23;
  console.log(a);
}

foo () ; 
console.log(a);

执行结果如下:

23 
Uncaught ReferenceError: a is not  defined

由于 a 是在函式 foo 中宣告, 所以叫用 foo 函式时可以取用变数 a , 但是在函式外取用变数 a 就会引发未定义识别字的错误。

全域变数

如果在函式外使用 var 宣告变数, 它就会变成全域变数, 在程式内任何地方都可以取用, 例如:

var a = 23 ;

function  foo ()  {
  console.log(a);
  a = 24;
}

foo () ; 
console.log(a);

执行结果如下:

宣告与设定初值分离

你也可以把宣告和设定初值分开来, 不一定要同时完成, 像是这样:

var a;
a = 23 ;
 console .log(a);

如果你希望在同一个地方集中宣告变数, 但是在要用到该变数的时候才设定值, 这样的写法就会很有用。

重复宣告

你也可以重复宣告同一个变数, 只要没有设定新的值, 就会保留原值, 例如:

var a = 23 ;
 console .log(a);
 var a;
 console .log(a);
 var a = 24 ;
 console .log(a);

执行结果如下:

第三行虽然重新宣告 a , 但是没有重新设定值, 所以 a 仍然是23。

变数提升(variable hoisting)

变数有一个我其实不知道有什么用途, 但是很多人喜欢拿来考别人的功能, 叫做 , 会把宣告变数的动作提升到执行其他程式前先完成, 意思就是在进入变数的有效范围内时, 会在执行第一行程式前就先宣告变数。因此, 在执行第一行程式的时候, 变数就已经存在了。例如: 變數提升 (variable hoisting)

console .log(a);
 var a = 23 ;
 console .log(a);

执行结果如下:

undefined 
23

由于在执行第一行程式前, 就会先宣告变数, 因此第一行程式并不会引发变数尚未宣告的错误。不过对于以 var 宣告的变数, 变数提升 只会先宣告变数, 并不会执行设定初值的程式, 以上例来说就是不会执行 , 而是设定初值为 , 所以你会看到第一行印出 的值是 。等执行到第二行才会设定变数 的值为23, 因此第三行就会印出23 了。 a = 23undefinedaundefineda

全域变数会成为全域物件的属性

以 var 宣告的全域变数会成为全域物件的属性, 例如:

var a = 23 ;
 console .log(globalThis.a);

执行结果如下:

不过这个属性是 不可设定(non-configurable) 的, 也就是不能使用 移除, 例如以下的程式虽然不会发生错误, 但是 却没有作用: delete delete

var a = 23;
 delete a;
 delete globalThis.a;
console.log(a);

执行结果 a 仍然存在, 印出的值也是正确的:

如果采用严格模式, 就会看到错误讯息:

'use strict' ;

var a = 23 ;
 delete globalThis.a;
 console .log(a);

执行结果如下:

Uncaught TypeError: property  "a"  is non-configurable and can 't be deleted

使用let 宣告区块层级的变数

所谓的区块, 就是由一对大括号括起来的区域, 使用 宣告的变数只要出了所在的区块, 就会失效, 例如: let

{
   let a = 23 ;
  console. log (a);
}

console. log (a);

执行结果如下:

23 
Uncaught ReferenceError: a is not  defined

由于第二次取用 a 时已经离开了宣告变数的区块, 因此变数 a 已经失效, 就会引发未定义识别字的错误。

分辨区块

在大部分的情况下, 我们很容易辨识区块, 不过在像是 for 的叙述中, 初始设定也是区块的一部份, 因此在初始设定内宣告的变数在 for 结束后也一样会失效, 例如:

for (let i = 0 ; i < 2 ; i ++)
{
  console.log(i);
}

console. log ( i );

执行结果如下:

0 
1 
Uncaught ReferenceError: i is not  defined

如果改用 var 宣告变数, 由于并没有离开函式范围, 所以不会引发错误, 例如:

for (var i = 0 ; i < 2 ; i ++)
{
  console.log(i);
}

console. log ( i );

执行结果最后会印出回圈结束时的 i 值:

全域变数

在任何区块外使用 let 建立的变数一样是全域变数, 可在程式中任何地方取用, 例如:

let i = 0 ;

for ( i = 0 ; i < 2 ; i ++) {}

console. log ( i );

结果如下:

不能重复宣告变数

变数提升不会设定初值

以 let 宣告变数也一样具有变数提升功能, 但是并不会设定初值, 在使用变数前一定要先透过 let 宣告, 例如:

console. log (a);
 let a = 0 ;

执行时就会引发错误:

Uncaught ReferenceError: can 't access lexical declaration ' a ' before initialization

表示不能在设定初值前就取用已宣告的变数 a 。

以let 宣告的变数不会成为全域物件的属性

以 let 宣告的变数并不会像是以 var 宣告的变数那样成为全域物件的属性, 例如:

let a = 23 ;
console. log (globalThis.a);

执行时印出的并不是 a 的值, 而是 undefined :

undefined

表示全域物件中并没有 a 这个属性。

使用const 宣告不能变更的变数

你也可以使用 宣告变数, 不过这种变数如同 字面所示, 是不能变的, 中文翻译为 常数 。先来看看以下的例子: const const

const a = 23 ;
console. log (a);
a = 24 ;

执行后如下:

23 
Uncaught TypeError: invalid assignment to  const  'a'

在第三行尝试设定常数内容时就会引发错误, 告诉你不能设定以 const 宣告的常数。

宣告常数时一定要设定值

以 const 宣告常数时必须一并设定初值, 不能将宣告与设定初值分开进行, 像是以下的例子就会引发错误:

const a;
a = 23 ;
console. log (a);

执行结果如下:

Uncaught SyntaxError : missing = in  const declaration

错误讯息告诉我们在 const 宣告时少了设定初值的 = 。

变更常数所参照的物件

请特别注意, 不能变更以 const 宣告的常数指的是不能重新设定常数本身, 如果常数的内容是一个物件, 你还是可以变更物件内的属性, 例如:

const a = {name: "John" };
a.name = "Mary" ;
console. log (a);

执行结果如下:

Object { name : "Mary" }

由于变更的是物件的内容, 而不是变更常数 a , 所以可以成功执行。同样的道理, 如果常数的内容是一个阵列, 也可以变更阵列内的项目:

const a = [ 1 , 2 , 3 ];
a.push( 4 );
a[ 0 ] = 10 ;
console. log (a);

执行结果如下:

Array ( 4 ) [ 10, 2, 3, 4 ]

除了不能重新设值外, const 跟 let 是一样的。

没有宣告直接设定变数

JavaScript 是很宽松的, 你甚至会看到有些程式中根本 没有宣告就直接设定变数的值 , 像是这样:

a = 23;
console.log(a);

执行时并不会引发错误, 而且可以正确印出 a 的值:

你甚至还可以随意在函式或是区块直接用同样的方式运作:

function  foo ()  {
  a = 23
}

{
  b = 24
}

foo () 
console . log (a) ; 
console.log(b);

执行结果如下:

你会看到 a 和 b 虽然是在函式以及区块内设定, 可是不像是 var 或是 let 有范围的限制, 两个都变成全域变数那样可以在任何地方使用。

未宣告的变数其实是全域物件的属性

之所以会有前述范例的结果, 是因为当JavaScript 看到识别字时, 会一层层的往外找寻是否有符合该名称的宣告, 例如:

let a = 23

function  foo () {
   console .log(a)
  b = 24 ;
  {
    c = 25 ;
    {
      console .log(b)
    }
  }
}

foo();

执行结果如下:

在 foo 函式中因为没有宣告 a , 所以会往上一层找到全域变数 a ;而最内层区块列印的 b 也是往上一层区块找到的 b 。

如果在全域变数里也找不到, 就会往 全域物件 globalThis 找它的属性, 这也是为什么你可以直接以 alert 叫用定义在 globalThis 物件内的 alert :

alert ( 'call globalThis.alert' );
 globalThis .alert ( 'property of globalThis' );

以上两种写法其实是一样的, 当JavaScript 看到 alert 时, 会发现程式中并没有定义 alert 函式, 因此会往全域物件 globalThis 寻找, 发现全域物件有 alert 属性, 因此变成叫用 globalThis.alert 。

在设定值的时候也是一样, 对于没有宣告过的识别字, JavaScript 会将之当成是要设定全域物件的属性, 例如:

a = 23 ;
globalThis.b = 24 ;
console. log (globalThis.a);
console. log (b);

执行结果如下:

第一行要设定 a 时, 会发现程式中没有宣告过 a , 因此实际上执行的是 globalThis.a = 23 , 你可以在第三行看到透过 globalThis.a 取用的就是同一份资料。相同的道理, 第二行虽然是设定 globalThis 的 b 属性, 但是在第四行却可以像是使用变数一样直接以 b 来取得属性值。

你可以在任何地方用这种方式帮全域物件增加属性, 并且以像是全域变数的方式使用该属性。也就是说, 若不使用 var 、 let 、 const 宣告而直接设定值, 并不会建立变数, 而是 设定全域物件 globalThis 的属性 。这样的作法看起来好像很方便, 随时想用就用, 但是却容易造成混淆, 搞不清楚到底是在哪里设定初值, 若要避免这个问题, 可以强制使用 严格模式 , 例如:

'use strict' 
a = 23 ;
 console .log(a);

执行时就会引发错误:

Uncaught ReferenceError: assignment to undeclared variable a

它会认为你是设值给一个未宣告的变数。

var 全域变数与纯全域物件属性的差异

你可能会想到, 前面不是有提到以 var 宣告的全域变数也会变成全域物件的属性, 这样和刚刚提到单纯全域物件的属性不是一样吗?还记得前面说明过, 以 var 宣告的全域变数会成为全域物件中不可设定的属性, 具体的表现就是你无法用 delete 移除它, 但若是纯全域物件的属性, 就可以用 delete 移除, 例如:

globalThis. a = 23 
console. log ( a )
 delete  a 
console. log ( a )

执行结果如下:

23 
Uncaught ReferenceError: a is not  defined

第二次要列印 a 时, 就会因为第三行已经将 a 移除变成未定义的识别字而引发错误。

这样的差异很合理, 因为以 var 宣告的全域变数是真的全域变数, 如果可以删除, 就不再是可以在程式中任何地方取用的全域变数了, 但是全域物件本来就是一个JavaScript 物件, 自然可以随意增删属性。

小结

以上我们就把宣告变数的几种方法介绍完了, 希望有助于厘清为什么这里可以使用这个变数、或者是为什么这个变数变成没有定义的疑惑。简单来说, 为了避免意外, 建议在程式中都只以 let 、 const 宣告, 不要使用 var , 也不要随意帮全域物件新增属性。

链接: https://www.fly63.com/article/detial/11729

css自定义变量_初次接触CSS变量

本文的目的主要是展示CSS变量是如何工作的。随着Web应用程序变得越来越大,CSS变得越来越大,越来越多,而且很多时候都很乱,在良好的上下文中使用CSS变量,为您提供重用和轻松更改重复出现的CSS属性的机制。

CSS变量(自定义属性)实践指南

Sass和Less这样的预处理器,让我们的CSS代码保持良好的结构和可维护性。像变量、混合(mixins)、循环控制等特性,增强了动态编写CSS的能力,从而减少重复代码,也加快了我们开发速度。

css变量_原生css 中变量的使用

原生css 中变量的使用,这个重要的 CSS 新功能,所有主要浏览器已经都支持了。本文全面介绍如何使用它,你会发现原生 CSS 从此变得异常强大。声明变量的时候,变量名前面要加两根连词线(--),var()函数用于读取变量。

理解var let const区别

JavaScript中var、let、const区别?js中let和const都是es5版本新的命名规范,在此之前定定义一个变量只能用var。我们可以把let和const看做是为了弥补var的一些不足而新设计出来的

一个例子,变量提升和函数提升就是这么简单!

引擎在读取js代码的过程中,分为两步。第一个步骤是整个js代码的解析读取,第二个步骤是执行。在JS代码执行之前,浏览器的解析器在遇到 var 变量名 和function 整个函数 提升到当前作用域的最前面。

CSS变量使用解析

很早直接就了解到CSS变量相关的内容,奈何之前使用价值不高(很多主流浏览器不兼容),最近发现主流浏览器都已经支持了这一变化,CSS变量就像JS的变量,每个类名或者花括号就像一个function,里面的变量只有上下文以内可以获取,这就让CSS有了更多可能性。

let与var的区别,为什么要用let?

var是全局声明,let是块级作用的,只适用于当前代码块;var变量会发生变量提升,let则不会进行变量提升;var 会造成重复赋值,循环里的赋值可能会造成变量泄露至全局

ES6-变量的解构赋值

解构赋值官方解释:按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。变量的解构赋值就是一种写法,掌握了这种写法可以让我们在书写 javascript 代码时可以更加的简单,迅捷。

JS中变量的存储

JS中的变量是保存在栈内存中的:1.基本数据类型的值直接在栈内存中存储;2.值与值之间是独立存在的,修改一个变量不会影响其他变量;对象是保存到堆内存中的,每创建一个新的对象

js 交换变量值的方法总汇

这篇文章总结七种办法来交换a和b的变量值 。最最最简单的办法就是使用一个临时变量了 ,最后我的方案是利用了ES6的解构赋值语法 ,它允许我们提取数组和对象的值,对变量进行赋值

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!