溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript三大變量聲明實(shí)例分析

發(fā)布時(shí)間:2022-06-06 09:49:31 來源:億速云 閱讀:100 作者:zzz 欄目:開發(fā)技術(shù)

這篇文章主要講解了“JavaScript三大變量聲明實(shí)例分析”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JavaScript三大變量聲明實(shí)例分析”吧!

Var

var 操作符用于定義變量(var 也是一個(gè)關(guān)鍵字),后跟變量名(即標(biāo)識符)

基礎(chǔ)寫法

聲明未定義值

這里定義了一個(gè)名為test的變量,可以用它保存任何類型的值

 var test;

注意: 不初始化的情況下,變量會保存一個(gè)特殊值 undefined

聲明定義值

ECMAScript 實(shí)現(xiàn)變量初始化,因此可以同時(shí)定義變量并設(shè)置它的值,如下:

 // 聲明定義值
 var test = "good job";

像這樣的初始化變量不會將它標(biāo)識為字符串類型,隨時(shí)可以改變保存的值,從而改變值的類型。

不推薦寫法

在下面這個(gè)例子中,變量 test 首先被定義為一個(gè)保存字符串值的變量,然后又被重寫為保存了數(shù)值:

 var test = "good job";  
 test = 299;  //合法,但不推薦
 /* 像這種單獨(dú)的變量可以直接賦值就沒必要另起去改了 沒必要 */

雖然不推薦改變變量保存值的類型,但這在 ECMAScript 中是完全有效的。

var 聲明作用域

使用 var 定義的變量會成為包含它的函數(shù)的局部變量,簡稱為作用域變量。

局部作用域

使用 var 在一個(gè)函數(shù)內(nèi)部定義一個(gè)變量,就意味著該變量將在函數(shù)退出時(shí)被銷毀,如下:

 function fun() { 
  var test = "Hello World"; // 局部變量
 } 
 fun(); 
 console.log(test); // 出錯(cuò)!

這里,test 變量是在函數(shù)內(nèi)部使用 var 定義的,函數(shù)為 fun(),調(diào)用它會創(chuàng)建這個(gè)變量并給它賦值;調(diào)用之后變量隨即被銷毀,因此示例中的最后一行會導(dǎo)致錯(cuò)誤。

全局作用域

在函數(shù)內(nèi)定義變量時(shí)省略 var 操作符,可以創(chuàng)建一個(gè)全局變量,如下

 function fun() { 
  test = "Hello World"; // 局部變量
 } 
 fun(); 
 console.log(test); // "Hello World"

去掉之前的 var 操作符之后,test 就變成了全局變量;只要調(diào)用一次函數(shù) fun(),就會定義這個(gè)變量,并且可以在函數(shù)外部訪問到。

注意:雖然可以通過省略 var 操作符定義全局變量,但不推薦這么做。

在嚴(yán)格模式下,如果像這樣給未聲明的變量賦值,則會導(dǎo)致拋出 ReferenceError。

便捷語法

如果需要定義多個(gè)變量,可以在一條語句中用逗號分隔每個(gè)變量(及可選的初始化),如下:

 var name = "hey~~", 
     name = "shrimpsss", 
     age = 99;

這里定義并初始化了 3 個(gè)變量,因?yàn)?nbsp;ECMAScript 是松散類型的,所以使用不同數(shù)據(jù)類型初始化的變量可以用一條語句來聲明; 雖然插入換行和空格縮進(jìn)并不是必需的,但這樣有利于閱讀理解。

注意: 在嚴(yán)格模式下,不能定義名為 eval 和 arguments 的變量,否則會導(dǎo)致語法錯(cuò)誤。

var 聲明提升

var 這個(gè)關(guān)鍵字在函數(shù)中聲明變量時(shí)會自動提升到函數(shù)作用域頂部,如下:

 function foo() { 
  console.log(age); 
  var age = 26; 
 } 
 foo(); // undefined

之所以不會報(bào)錯(cuò),是因?yàn)?nbsp;ECMAScript 運(yùn)行時(shí)把它看成等價(jià)于如下代碼:

 function foo() { 
  var age; 
  console.log(age); 
  age = 26; 
 } 
 foo(); // undefined

這就所謂的“提升”(hoist),也就是把所有變量聲明都拉到函數(shù)作用域的頂部。

Let

let 跟 var 的作用差不多,但 let 聲明的范圍是塊作用域(var 聲明的范圍是函數(shù)作用域)

塊作用域是函數(shù)作用域的子集,因此適用于 var 的作用域限制同樣也適用于 let

let 作用域

let 作用域只能在塊作用域里訪問,不能跨塊訪問,也不能跨函數(shù)訪問

兩者的對比會更加凸顯不一,如下:

 // --- var ---
 if (true) { 
  var name = 'king'; 
  console.log(name); // Matt 
 } 
 console.log(name); // Matt
 
 // --- let ---
 if (true) { 
  let age = 26; 
  console.log(age); // 26 
 } 
 console.log(age); // ReferenceError: age 沒有定義

在這里,age 變量之所以不能在 if 塊外部被引用,是因?yàn)樗淖饔糜騼H限于該塊內(nèi)部。

冗余聲明

let 不允許同一個(gè)塊作用域中出現(xiàn)冗余聲明

 var name; 
 var name; 
 let age; 
 let age; // SyntaxError;標(biāo)識符 age 已經(jīng)聲明過了

冗余聲明的報(bào)錯(cuò)不會因混用 let 和 var 而受影響。

這兩個(gè)關(guān)鍵字聲明的并不是不同類型的變量,它們只是指出變量在相關(guān)作用域如何存在,如下:

 var name; 
 let name; // SyntaxError 
 let age; 
 var age; // SyntaxError

JavaScript 引擎會記錄用于變量聲明的標(biāo)識符及其所在的塊作用域,因此嵌套使用相同的標(biāo)識符不會報(bào)錯(cuò)。

暫時(shí)性死區(qū)

let 與 var 的另一個(gè)重要的區(qū)別,就是 let 聲明的變量不會在作用域中被提升

 // name 會被提升
 console.log(name); // undefined 
 var name = 'vito'; 
 
 // age 不會被提升
 console.log(age); // ReferenceError:age 沒有定義
 let age = 26

在解析代碼時(shí),JavaScript 引擎也會注意出現(xiàn)在塊后面的 let 聲明,只不過在此之前不能以任何方式來引用未聲明的變量。

在 let 聲明之前的執(zhí)行瞬間被稱為“暫時(shí)性死區(qū)”(temporal dead zone),在此階段引用任何后面才聲明的變量都會拋出 ReferenceError。

全局聲明

與 var 關(guān)鍵字不同,使用 let 在全局作用域中聲明的變量不會成為 window 對象的屬性

 /* window.xx:在window對象中查找此屬性(元素)*/
 var name = 'vito'; 
 console.log(window.name); // 'vito' 
 
 let age = 26; 
 console.log(window.age); // undefined

但 let 聲明仍然是在全局作用域中發(fā)生的,所以相應(yīng)變量會在頁面的生命周期內(nèi)存續(xù)。

條件聲明

因?yàn)?let 的作用域是塊,所以不可能檢查前面是否已經(jīng)使用 let 聲明過同名變量,同時(shí)也就不可能在沒有聲明的情況下聲明它,沒有與var 一樣的聲明提升。

 /* 方便理解: 把兩個(gè)<script>代碼塊看做一個(gè)代碼塊 */
 
 <script> 
  var name = 'Nicholas'; 
  let age = 26; 
 </script> 
 
 <script> 
  // 假設(shè)腳本不確定頁面中是否已經(jīng)聲明了同名變量
  // 那它可以假設(shè)還沒有聲明過
  var name = 'Matt'; 
  // 這里沒問題,因?yàn)榭梢员蛔鳛橐粋€(gè)提升聲明來處理
  // 不需要檢查之前是否聲明過同名變量
  let age = 36; 
  // 如果 age 之前聲明過,這里會報(bào)錯(cuò)
 </script>

為此, let 這個(gè)新的 ES6 聲明關(guān)鍵字,不能依賴條件聲明模式

注意: let 不能進(jìn)行條件式聲明是件好事,因?yàn)闂l件聲明是一種反模式,它讓程序變得更難理解

for 循環(huán)中的 let

在 let 出現(xiàn)之前,for 循環(huán)定義的迭代變量會滲透到循環(huán)體外部。

常見for循環(huán)

如下,用 var 示例:

 for (var i = 0; i < 5; ++i) { 
  // 循環(huán)邏輯 
 } 
 console.log(i); // 5

改成使用 let 就不會有這個(gè)問題了,因?yàn)?nbsp;let 迭代變量的作用域僅限于 for 循環(huán)塊內(nèi)部:

 for (let i = 0; i &lt; 5; ++i) { 
  // 循環(huán)邏輯
 } 
 console.log(i); // ReferenceError: i 沒有定義
for循環(huán)套定時(shí)器

在使用 var 的時(shí)候,最常見的問題就是對迭代變量的奇特聲明和修改,如下:

 for (var i = 0; i < 5; ++i) { 
  setTimeout(() => console.log(i), 0) 
 } 
 // 實(shí)際上會輸出 5、5、5、5、5

怎么樣,是不是以為會輸入 0、1、2、3、4 ?

之所以會這樣,是因?yàn)樵谕顺鲅h(huán)時(shí),迭代變量保存的是導(dǎo)致循環(huán)退出的值:5。在之后執(zhí)行超時(shí)邏輯時(shí),所有的 i 都是同一個(gè)變量,因而輸出的都是同一個(gè)最終值。

而在使用 let 聲明迭代變量時(shí),JavaScript 引擎在后臺會為每個(gè)迭代循環(huán)聲明一個(gè)新的迭代變量。

 for (let i = 0; i < 5; ++i) { 
  setTimeout(() => console.log(i), 0) 
 } 
 // 會輸出 0、1、2、3、4

每個(gè) setTimeout 引用的都是不同的變量實(shí)例,所以 console.log 輸出的是我們期望的值,也就是循環(huán)執(zhí)行過程中每個(gè)迭代變量的值。

這種每次迭代聲明一個(gè)獨(dú)立變量實(shí)例的行為適用于所有風(fēng)格的 for 循環(huán),包括 for-in 和 for-of循環(huán)。

const

const跟 let 的行為差不多,但區(qū)別是用它聲明變量時(shí)必須同時(shí)初始化變量,且嘗試修改 const 聲明的變量會導(dǎo)致運(yùn)行時(shí)錯(cuò)誤(一致性)

const 限制

  • const 不可改值

 const age = 26; 
 age = 36; // TypeError
  • const 也不允許重復(fù)聲明

 const name = 'Lisa'; 
 const name = 'Vito'; // SyntaxError
  • const 聲明的作用域也是塊

 const name = 'apple'; 
 if (true) { 
  const name = 'avocado'; 
 } 
 console.log(name); // apple

const 聲明的限制只適用于它指向的變量的引用。 換句話說,如果 const 變量引用的是一個(gè)對象,那么修改這個(gè)對象內(nèi)部的屬性并不違反 const 的限制,如下:

 const person = {}; 
 person.name = 'vito'; // ok

怎么樣,是不是很神奇 o( ̄▽ ̄)d

for 循環(huán)中的 const

JavaScript 引擎會為 for 循環(huán)中的 let 聲明分別創(chuàng)建獨(dú)立的變量實(shí)例,雖然 const 變量跟 let 變量很相似,但是不能用 const 來聲明迭代變量(因?yàn)榈兞繒栽觯?/p>

 for (const i = 0; i < 10; ++i) {}  // TypeError 類型錯(cuò)誤

不過,如果你只想用 const 聲明一個(gè)不會被修改的 for 循環(huán)變量,那也是可以的。

每次迭代只是創(chuàng)建一個(gè)新變量,這對 for-of 和 for-in 循環(huán)特別有意義的,如下:

 let i = 0; 
 for (const j = 7; i < 5; ++i) { 
  console.log(j); 
 } 
 // 7, 7, 7, 7, 7 
 
 for (const key in {a: 1, b: 2}) { 
  console.log(key); 
 } 
 // a, b 
 
 for (const value of [1,2,3,4,5]) { 
  console.log(value); 
 } 
 // 1, 2, 3, 4, 5

聲明風(fēng)格及最佳實(shí)踐

ECMAScript 6 增加 let 和 const 為這門語言更精確地聲明作用域和語義提供了更好的支持

  • 不使用 var

有了 let 和 const,大多數(shù)開發(fā)者會發(fā)現(xiàn)自己不再需要 var 了。限制自己只使用 let 和 const 有助于提升代碼質(zhì)量,因?yàn)樽兞坑辛嗣鞔_的作用域、聲明位置,以及不變的值。

  • const 優(yōu)先,let 次之

使用 const 聲明可以讓瀏覽器運(yùn)行時(shí)強(qiáng)制保持變量不變,也可以讓靜態(tài)代碼分析工具提前發(fā)現(xiàn)不合法的賦值操作。因此,應(yīng)該優(yōu)先使用 const 來聲明變量,只在提前知道未來會有修改時(shí),再使用 let。

感謝各位的閱讀,以上就是“JavaScript三大變量聲明實(shí)例分析”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JavaScript三大變量聲明實(shí)例分析這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI