摘要:聲明會組織對變量綁定和對自生值的修改,這意味著聲明并不會組織對變量成員的修改。循環中的塊級綁定在此處仍然可被訪問輸出的結果并不是預期的值而是是因為聲明導致的變量的提升。全局塊級綁定與不同于的另一個方面是在全局作用域上的表現。
變量聲明一直是js工作中最微妙的一部分,它不像C語言一樣,變量總是在被它創建的時候聲明,js語言可以允許你在你需要聲明變量的時候進行聲明。
var let const 之變量聲明
var 聲明與變量提升。
當我們使用var關鍵字進行變量聲明的時候,無論變量聲明的位置在哪里,都會被是為聲明于所在的函數的頂部(如果不在函數內的話,則視為在全局作用域的頂部)這就是所謂的變量提升(hoisting)var提升如下:
function getValue(condition) { if (condition) { var value = "blue"; // 其他代碼 return value; } else { // value 在此處可訪問,值為 undefined return null; } // value 在此處可訪問,值為 undefined }
塊級聲明let
塊級聲明也就是讓所聲明的變量在指定的作用域外無法被訪問到,塊級作用域在如下情況下被創建在一個函數內部,
在一個代碼塊(由一對花括號包裹)內部
let聲明的語法和var聲明一致,由于let聲明不會將變量提升到函數頂部,因此我們需要手動將let聲明放置到頂部,以便讓變量在整個代碼塊內部可用。如下所示:
function getValue(condition) { if (condition) { let value = "blue"; // 其他代碼 return value; } else { // value 在此處不可用 return null; } // value 在此處不可用 }禁止重復標識
如果一個標識符已經在代碼內部被定義,重復進行let聲明會報錯
var a = 30; //報錯 let a = 30;a變量被聲明了兩次:一次使用 var ,另一次使用 let 。因為 let 不能在同一作用域內重復聲明一個已有標識符,此處的 let 聲明就會拋出錯誤。另一方面,在嵌套的作用域內使用 let 聲明一個同名的新變量,則不會拋出錯誤,以下代碼對此進行了演示:
var count = 30; // 不會拋出錯誤 if (condition) { let count = 40; // 其他代碼 }這段代碼中不會拋錯,關鍵點在于let在同一級代碼塊中重復聲明會報錯 const常量聲明 在es6中可以使用const語法進行聲明。使用const聲明的變量會被認為是常量(constant),意味著他們的值在被設置完成后既不能再被改變。正因為如此,所有的const的變量都需要在聲明時進行初始化,
// 有效的常量 const maxItems = 30; // 語法錯誤:未進行初始化 const name;maxItems 變量被初始化了,因此它的 const 聲明能正常起效。而 name 變量沒有被初始化,導致在試圖運行這段代碼時拋出了錯誤。const聲明會組織對變量綁定和對自生值的修改,這意味著const聲明并不會組織對變量成員的修改。例如:
const person = { name: "Nicholas" }; // 工作正常 person.name = "Greg"; // 拋出錯誤 person = { name: "Greg" };const聲明和let聲明的對比
首先他們都是塊級聲明,這就意味著常量在聲明它們的語句塊外是無法被訪問的,并且聲明也不會被提升,示例如下:
if (condition) { const maxItems = 5; // 其他代碼 } // maxItems 在此處無法訪問
它們在統一級作用域中重復聲明時會導致拋出錯誤
暫時性死區 當我們使用let或者const 進行聲明的時候,在到達聲明處之前都是無法訪問的,如果我們試圖訪問會導致一個引用錯誤。出項這個問題是因為暫時性死區 當JS 引擎檢視接下來的代碼塊并發現變量聲明時,它會在面對 var 的情況下將聲明提升到函數或全局作用域的頂部,而面對 let 或 const 時會將聲明放在暫時性死區內。任何在暫時性死區內訪問變量的企圖都會導致“運行時”錯誤(runtime error)。只有執行到變量的聲明語句時,該變量才會從暫時性死區內被移除并可以安全使用。 循環中的塊級綁定for (var i = 0; i < 10; i++) { process(items[i]); } // i 在此處仍然可被訪問 console.log(i); // 10
輸出的結果并不是預期的值而是10;是因為var聲明導致的變量的提升。聰明的你肯定會想到使用塊級綁定來進行變量聲明
for (let i = 0; i < 10; i++) { process(items[i]); } console.log(i);
i在此處是不是會正常輸出呢,其實不會,在這個例子中會導致報錯,為什么呢?因為i在此處不可訪問。本例中的變量 i 僅在 for 循環內部可用,一旦循環結束,該變量在任意位置都不可訪問。
我們在來看看一下代碼
var funcs = []; for (var i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } funcs.forEach(function(func) { func(); // 輸出數值 "10" 十次 });
你原本可能預期這段代碼會輸出 0 到 9 的數值,但它卻在同一行將數值 10 輸出了十次。這是
因為變量 i 在循環的每次迭代中都被共享了,意味著循環內創建的那些函數都擁有對于同一
變量的引用。在循環結束后,變量 i 的值會是 10 ,因此當 console.log(i) 被調用時,
每次都打印出 10 。
為了修正這個問題,開發者在循環內使用立即調用函數表達式(IIFEs),以便在每次迭代中
強制創建變量的一個新副本,示例如下:
var funcs = []; for (var i = 0; i < 10; i++) { funcs.push((function(value) { return function() { console.log(value); } }(i))); } funcs.forEach(function(func) { func(); // 從 0 到 9 依次輸出 });循環內的 let 聲明
let 聲明通過有效模仿上例中 IIFE 的作用而簡化了循環。在每次迭代中,都會創建一個新的
同名變量并對其進行初始化。這意味著你可以完全省略 IIFE 而獲得預期的結果,就像這樣
var funcs = []; for (let i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } funcs.forEach(function(func) { func(); // 從 0 到 9 依次輸出 })
我們是否會想到這個問題:為什么同樣的代碼使用let聲明會導致不一樣的結果呢?
在循環中let聲明每次都創建了一個新的i變量,因此在循環內部創建的函數獲得了各自的i副本,而每個i副本的值都會在每次的循環迭代聲明變量的時候確定了
var funcs = [], object = { a: true, b: true, c: true }; for (let key in object) { funcs.push(function() { console.log(key); }); } funcs.forEach(function(func) { func(); // 依次輸出 "a"、 "b"、 "c" });
本例中的 for-in 循環體現出了與 for 循環相同的行為。每次循環,一個新的 key 變量綁
定就被創建,因此每個函數都能夠擁有它自身的 key 變量副本,結果每個函數都輸出了一個
不同的值。而如果使用 var 來聲明 key ,則所有函數都只會輸出 "c" 。
let 聲明在循環內部的行為是在規范中特別定義的,而與不提升變
量聲明的特征沒有必然聯系。事實上,在早期 let 的實現中并沒有這種行為,它是后來
才添加的。
雖然es6沒有明確的規范我們不能在for循環中使用const聲明,然而它會根據循環方式的不同而有不同的行為,我們可以在初始化時使用const,但是當循環試圖改變變量的值的時候會拋出錯誤,例如:
var funcs = []; // 在一次迭代后拋出錯誤 for (const i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); }
在此代碼中, i 被聲明為一個常量。循環的第一次迭代成功執行,此時 i 的值為 0 。在
i++ 執行時,一個錯誤會被拋出,因為該語句試圖更改常量的值。因此,在循環中你只能使
用 const 來聲明一個不會被更改的變量
而另一方面, const 變量在 for-in 或 for-of 循環中使用時,與 let 變量效果相同。因
此下面代碼不會導致出錯:
var funcs = [], object = { a: true, b: true, c: true }; // 不會導致錯誤 for (const key in object) { funcs.push(function() { console.log(key); }); } funcs.forEach(function(func) { func(); // 依次輸出 "a"、 "b"、 "c" });
這段代碼與“循環內的 let 聲明”小節的第二個例子幾乎完全一樣,唯一的區別是 key 的值在
循環內不能被更改。 const 能夠在 for-in 與 for-of 循環內工作,是因為循環為每次迭
代創建了一個新的變量綁定,而不是試圖去修改已綁定的變量的值(就像使用了 for 而不是
for-in 的上個例子那樣)。
let 與 const 不同于 var 的另一個方面是在全局作用域上的表現。當在全局作用域上使 用 var 時,它會創建一個新的全局變量,并成為全局對象(在瀏覽器中是 window )的一 個屬性。總結 let和const塊級作用域的引入,能夠使我們減少很多無心的錯誤,它們的一個副作用,是不能在變量聲明位置之前訪問它們 塊級綁定當前的最佳實踐就是:在默認情況下使用 const ,而只在你知道變量值需要被更改的情況下才使用 let 。這在代碼中能確?;緦哟蔚牟豢勺冃?,有助于防止某些類型的錯誤。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103124.html
摘要:眾所周知,中的聲明存在變量提升機制,因此引用了塊級作用域來強化對變量生命周期的控制聲明不會被提升,有幾個需要注意的點不能被重復聲明假設作用域中已經存在某個標識符無論該標識符是通過聲明還是變量聲明,此時再使用或關鍵定聲明會拋錯此處則會拋出錯誤 眾所周知,js中的var聲明存在變量提升機制,因此ESMAScript 6引用了塊級作用域來強化對變量生命周期的控制let const 聲明不會被...
摘要:聲明變量不存在變量提升。臨時死區,而且不能在聲明之前訪問它。禁止重復聲明相同的變量,否則報錯。不存在變量提升,一旦執行快外就會立即銷毀。聲明不允許修改綁定,但允許修改值,也就是說用創建對象后,可以修改該對象的屬性值。 知識點 var 聲明變量: 1、存在變量提升,實際上var無論在哪里聲明,都會被當做當前的作用域頂部聲明變量。 2、可以重復聲明,后聲明的變量會覆蓋前聲明的變量。 let...
摘要:塊級作用域存在于函數內部塊中字符和之間的區域和塊級聲明用于聲明在指定塊的作用域之外無法訪問的變量。和都是塊級聲明的一種。值得一提的是聲明不允許修改綁定,但允許修改值。這意味著當用聲明對象時沒有問題報錯臨時死區臨時死區,簡寫為。 塊級作用域的出現 通過 var 聲明的變量存在變量提升的特性: if (condition) { var value = 1; } console.lo...
摘要:聲明一個只讀的常量。的作用域與命令相同只在聲明所在的塊級作用域內有效。這在語法上,稱為暫時性死區,簡稱。暫時性死區也意味著不再是一個百分之百安全的操作。重復聲明是允許在相同作用域內重復聲明同一個變量的,而與不允許這一現象。 轉載自阮一峰老師的ES6入門,稍有修改 1.基本概念MDN var聲明了一個變量,并且可以同時初始化該變量。let語句聲明一個塊級作用域的本地變量,并且可選的賦予...
閱讀 781·2021-11-09 09:47
閱讀 1568·2019-08-30 15:44
閱讀 1143·2019-08-26 13:46
閱讀 2107·2019-08-26 13:41
閱讀 1266·2019-08-26 13:32
閱讀 3772·2019-08-26 10:35
閱讀 3519·2019-08-23 17:16
閱讀 448·2019-08-23 17:07