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