摘要:想閱讀更多優質文章請猛戳博客一年百來篇優質文章等著你引用規范作者一條最近的推特變量提升是一個陳舊且令人困惑的術語。變量提升部分提前激活是在和之前聲明變量的一種較老的方法。
為了保證可讀性,本文采用意譯而非直譯。
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!
引用 ES6 規范作者 Allen Wirfs-Brock一條最近的推特:
變量提升是一個陳舊且令人困惑的術語。甚至在 ES6
之前:變量提升的意思究竟是“提升至當前作用域頂部”還是“從嵌套的代碼塊中提升到最近的函數或腳本作用域中”?還是兩者都有?
受 Allen 啟發,本文提出了一種不同的方法來描述變量聲明。
1. 聲明:作用域與激活可以將聲明分為兩個方面:
作用域:在哪里可以看到聲明的變量? 這是一個靜態特征。
激活:我什么時候可以訪問變量? 這是一個動態特征:有些變量只要我們進入其作用域,就可以訪問。 有的,我們必須等到執行到它們的聲明。
下表總結了不同聲明的方式如何處理上述兩個方面。
“Duplicates”描述是否可以在同一作用域內聲明兩次。
“Global prop.”表示一個在 script 中的聲明,當全局作用域中被執行時,是否會向全局對象添加屬性。
TDZ 表示暫時性死區(稍后解釋)。 函數聲明在嚴格模式下是塊作用域的(例如在模塊內部),但在非嚴格模式下是函數作用域。
2. const 和 let :暫時性死區對于JavaScript,TC39 需要決定如果在聲明之前訪問其直接作用域中的常量會發生什么:
{ console.log(x); // 這里會發生什么? const x; }
主要有兩種種情況:
打印 undefined
報錯
第一種不會出現,因為 x 是一個常量,如果打印 undefined,在聲明前和聲明后它將擁有不同的值,x 就不是常量了。
let 和 const 都會出現第二種情況,就是會報錯。進入變量作用域與執行聲明之間的這段時間被稱為該變量的 臨時死區(TDZ):
在臨時死區中,變量被認為是未初始化的(就像它有一個特殊的值一樣)。
如果訪問未初始化的變量,將得到ReferenceError 錯誤。
一旦執行到變量聲明,該變量將被設置為初始化器的值(通過賦值符號指定),如果沒有初始化,則為undefined。
以下代碼說明了臨時死區:
if (true) { // 進入 `tmp` 的作用域,TDZ 開始 // `tmp` 未被初始化: assert.throws(() => (tmp = "abc"), ReferenceError); assert.throws(() => console.log(tmp), ReferenceError); let tmp; // TDZ 結束 assert.equal(tmp, undefined); }
下一個例子表明臨時死區只是 暫時的 (與時間有關):
if (true) { // 進入 `myVar` 作用域,TDZ 開始 const func = () => { console.log(myVar); // 稍后執行 }; // 我們在 TDZ 中: // 訪問 `myVar` 造成 `ReferenceError` let myVar = 3; // TDZ 結束 func(); // OK,在 TDZ 外調用 }
即使 func() 位于myVar聲明之前使用 myVar 變量,但我們也可以調用func(),前提是必須等到myVar的臨時死區結束。
函數聲明與提前激活函數聲明總是在進入它的作用域時執行,不管它位于作用域的什么位置。這使得能夠在函數foo()聲明之前調用它:
assert.equal(foo(), 123); // ok,相等 function foo() { return 123; }
提前激活 foo()意味著樓上的代碼等價于
function foo() { return 123; } assert.equal(foo(), 123);
如果用 const 或 let 聲明一個函數,它就不會被提前激活:在下面的例子中,你只能在 bar() 聲明后調用它。
assert.throws( () => bar(), // 聲明前 ReferenceError); const bar = () => { return 123; }; assert.equal(bar(), 123); // 聲明后在沒有提前激活的情況下提前調用
即使函數g()沒有提前激活,也可以被前面的函數 f()(在同一作用域內)調用 - 只要遵守以下規則:f() 必須在聲明 g() 之后調用
const f = () => g(); const g = () => 123; // g() 聲明后調用 f(): assert.equal(f(), 123);
模塊中的函數通常在模塊執行完后調用。 因此,在模塊中,很少需要擔心函數的順序。
最后,注意提前激活是怎樣自動執行以維持上述規則的:當進入一個作用域時,在任何函數被調用前,所有的函數聲明都會被先執行。
提前激活的一個陷阱如果依賴于提前激活機制,在函數聲明之前調用函數,那么需要注意的是它不會訪問未提前激活的變量。如下:
funcDecl(); const MY_STR = "abc"; function funcDecl() { console.log(MY_STR) }
上述會報錯:
如果你在 MY_STR 聲明之后調用 funcDecl() 就不會有問題。
提前激活的利弊我們已經看到提前激活有一個陷阱,你可以在不使用它的情況下獲得大部分好處。因此,最好避免提前激活。但我對此說法并非十分認同,如前所述,我經常使用函數聲明,因為我喜歡它們的語法。
類聲明不會提前激活類聲明不會提前激活:
assert.throws( () => new MyClass(), ReferenceError); class MyClass {} assert.equal(new MyClass() instanceof MyClass, true);
這是為什么? 考慮以下類聲明:
class MyClass extends Object {}
extends是可選的,它的操作數是一個表達式。 因此,您可以這樣做:
const identity = x => x; class MyClass extends identity(Object) {}
計算這樣的表達式必須在它被引用的地方完成,其它行為都會使人困惑。這解釋了為什么類聲明不提前激活。
var :變量提升(部分提前激活)var是在const和let之前聲明變量的一種較老的方法。考慮下面的var聲明。
var x = 123;
這個聲明包含兩個部分:
聲明var x:與大多數其他聲明一樣,var聲明變量的作用域是最內層的包圍函數,而不是最內層的包圍塊。這樣的變量在其作用域的開始時就已處于活動狀態,并使用undefined初始化。
賦值 x = 123 :賦值總是在適當位置執行。
以下代碼演示了 var :
function f() { // 部分提前激活: assert.equal(x, undefined); if (true) { var x = 123; // 賦值已經執行 assert.equal(x, 123); } // 作用域為函數作用域,非塊級作用域。 assert.equal(x, 123); }交流
干貨系列文章匯總如下,覺得不錯點個Star,歡迎 加群 互相學習。
https://github.com/qq44924588...
我是小智,公眾號「大遷世界」作者,對前端技術保持學習愛好者。我會經常分享自己所學所看的干貨,在進階的路上,共勉!
關注公眾號,后臺回復福利,即可看到福利,你懂的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75150.html
摘要:想閱讀更多優質文章請猛戳博客一年百來篇優質文章等著你引用規范作者一條最近的推特變量提升是一個陳舊且令人困惑的術語。變量提升部分提前激活是在和之前聲明變量的一種較老的方法。 為了保證可讀性,本文采用意譯而非直譯。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 引用 ES6 規范作者 Allen Wirfs-Brock一條最近的推特: 變量提升是一個陳舊且令人困惑的...
摘要:云計算有哪些技術特點很多技術宅的專家們曾經總結過云計算技術的一些特點,下面我們就來概述一下。目前,云計算技術在安全問題上已經有了長足的進步,通過對數據傳輸數據存儲數據審計三個環節采取相應的安全措施,從而保障整個云平臺的安全。 云計算當前處于何種現狀? 我們在談任何一種新技術的時候,用戶往往更關注技術所在領域的應用程度等問題,對于云計算來說,近些年在科研領域的應用已經取得了突飛猛進的進展,...
摘要:區塊鏈水平擴容的基本思想是將單根區塊鏈的狀態劃分為多條區塊鏈狀態。通過增加網絡中片的數量,整個區塊鏈網絡的吞吐量將會線性增加。的宗旨是通過以分片為代表的水平擴容技術,建立一個人人可用的區塊鏈底層公鏈。 目前,公鏈極低的交易處理能力(TPS)為人們便捷的使用區塊鏈帶來很大的麻煩。例如:比特幣網絡只支持6到7個TPS,而以太坊目前只能處理大約15 TPS,而中心化支付系統的代表:支付寶,在...
摘要:數組原理遍歷原理揭秘數組原理遍歷原理揭秘可見,數組其實已經改變了,但是遍歷出來的并沒有增加的哪一項。此時,我們也可以輸出一下當前指針位置數組原理遍歷原理揭秘數組原理遍歷原理揭秘數組指針停留在了位置上。 php中的中的數組跟js里面數組是不大一樣的。php中數組的下標可以整數也可以是字符串,而且數組中元素的順序不是由下標決定的,而是由添加元素的順序。數組基礎 $arr1 = array(...
閱讀 3012·2021-11-22 12:06
閱讀 599·2021-09-03 10:29
閱讀 6526·2021-09-02 09:52
閱讀 2013·2019-08-30 15:52
閱讀 3411·2019-08-29 16:39
閱讀 1190·2019-08-29 15:35
閱讀 2061·2019-08-29 15:17
閱讀 1416·2019-08-29 11:17