第八章:ES6以后

特別說(shuō)明丈积,為便于查閱赏陵,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS

在本書(shū)寫(xiě)作的時(shí)候步绸,ES6(ECMAScript 2015)的最終草案即將為了ECMA的批準(zhǔn)而進(jìn)行最終的官方投票悴晰。但即便是在ES6已經(jīng)被最終定稿的時(shí)候趋艘,TC39協(xié)會(huì)已經(jīng)在為了ES7/2016和將來(lái)的特性進(jìn)行努力的工作娇澎。

正如我們?cè)诘谝徽轮杏懻撨^(guò)的笨蚁,預(yù)計(jì)JS進(jìn)化的節(jié)奏將會(huì)從好幾年升級(jí)一次加速到每年進(jìn)行一次官方的版本升級(jí)(因此采用編年命名法)。這將會(huì)徹底改變JS開(kāi)發(fā)者學(xué)習(xí)與跟上這門語(yǔ)言腳步的方式趟庄。

但更重要的是括细,協(xié)會(huì)實(shí)際上將會(huì)一個(gè)特性一個(gè)特性地進(jìn)行工作。只要一種特性的規(guī)范被定義完成戚啥,而且通過(guò)在幾種瀏覽器中的實(shí)驗(yàn)性實(shí)現(xiàn)打通了關(guān)節(jié)奋单,那么這種特性就會(huì)被認(rèn)為足夠穩(wěn)定并可以開(kāi)始使用了。我們都被強(qiáng)烈鼓勵(lì)一旦特性準(zhǔn)備好就立即采用它猫十,而不是等待什么官方標(biāo)準(zhǔn)投票览濒。如果你還沒(méi)學(xué)過(guò)ES6,現(xiàn)在上船的日子已經(jīng)過(guò)了拖云!

在本書(shū)寫(xiě)作時(shí)贷笛,一個(gè)未來(lái)特性提案的列表和它們的狀態(tài)可以在這里看到(https://github.com/tc39/ecma262#current-proposals)。

在所有我們支持的瀏覽器實(shí)現(xiàn)這些新特性之前宙项,轉(zhuǎn)譯器和填補(bǔ)是我們?nèi)绾螛蚪铀鼈兊姆椒ǚ唷abel,Traceur尤筐,和其他幾種主流轉(zhuǎn)譯器已經(jīng)支持了一些最可能穩(wěn)定下來(lái)的ES6之后的特性汇荐。

認(rèn)識(shí)到這一點(diǎn),是時(shí)候看一看它們之中的一些了盆繁。讓我們開(kāi)始吧掀淘!

警告: 這些特性都處于開(kāi)發(fā)的各種階段。雖然它們很可能確定下來(lái)改基,而且將與本章的內(nèi)容看起來(lái)相似繁疤,但還是要抱著更多質(zhì)疑的態(tài)度看待本章的內(nèi)容。這一章將會(huì)在本書(shū)未來(lái)的版本中隨著這些(和其他的o跽)特性的確定而演化稠腊。

async function

我們?cè)诘谒恼碌摹癎enerators + Promises”中提到過(guò),generatoryield一個(gè)promise給一個(gè)類似運(yùn)行器的工具鸣哀,它會(huì)在promise完成時(shí)推進(jìn)generator —— 有一個(gè)提案是要為這種模式提供直接的語(yǔ)法支持架忌。讓我們簡(jiǎn)要看一下這個(gè)被提出的特性,它稱為async function我衬。

回想一下第四章中的這個(gè)generator的例子:

run( function *main() {
    var ret = yield step1();

    try {
        ret = yield step2( ret );
    }
    catch (err) {
        ret = yield step2Failed( err );
    }

    ret = yield Promise.all([
        step3a( ret ),
        step3b( ret ),
        step3c( ret )
    ]);

    yield step4( ret );
} )
.then(
    function fulfilled(){
        // `*main()` 成功地完成了
    },
    function rejected(reason){
        // 噢叹放,什么東西搞錯(cuò)了
    }
);

被提案的async function語(yǔ)法可以無(wú)需run(..)工具就表達(dá)相同的流程控制邏輯饰恕,因?yàn)镴S將會(huì)自動(dòng)地知道如何尋找promise來(lái)等待和推進(jìn)【觯考慮如下代碼:

async function main() {
    var ret = await step1();

    try {
        ret = await step2( ret );
    }
    catch (err) {
        ret = await step2Failed( err );
    }

    ret = await Promise.all( [
        step3a( ret ),
        step3b( ret ),
        step3c( ret )
    ] );

    await step4( ret );
}

main()
.then(
    function fulfilled(){
        // `main()` 成功地完成了
    },
    function rejected(reason){
        // 噢埋嵌,什么東西搞錯(cuò)了
    }
);

取代function *main() { ..聲明的,是我們使用async function main() { ..形式聲明俱恶。而取代yield一個(gè)promise的雹嗦,是我們await這個(gè)promise。運(yùn)行main()函數(shù)的調(diào)用實(shí)際上返回一個(gè)我們可以直接監(jiān)聽(tīng)的promise合是。這與我們從一個(gè)run(main)調(diào)用中拿回一個(gè)promise是等價(jià)的了罪。

你看到對(duì)稱性了嗎?async function實(shí)質(zhì)上是 generators + promises + run(..)模式的語(yǔ)法糖聪全;它們?cè)诘讓拥牟僮魇窍嗤模?/p>

如果你是一個(gè)C#開(kāi)發(fā)者而且這種async/await看起來(lái)很熟悉泊藕,那是因?yàn)檫@種特性就是直接由C#的特性啟發(fā)的∧牙瘢看到語(yǔ)言提供一致性是一件好事娃圆!

Babel、Traceur 以及其他轉(zhuǎn)譯器已經(jīng)對(duì)當(dāng)前的async function狀態(tài)有了早期支持鹤竭,所以你已經(jīng)可以使用它們了踊餐。但是,在下一節(jié)的“警告”中臀稚,我們將看到為什么你也許還不應(yīng)該上這艘船吝岭。

注意: 還有一個(gè)async function*的提案,它應(yīng)當(dāng)被稱為“異步generator”吧寺。你可以在同一段代碼中使用yieldawait兩者窜管,甚至是在同一個(gè)語(yǔ)句中組合這兩個(gè)操作:x = await yield y≈苫“異步generator”提案看起來(lái)更具變化 —— 也就是說(shuō)幕帆,它返回一個(gè)沒(méi)有還沒(méi)有完全被計(jì)算好的值。一些人覺(jué)得它應(yīng)當(dāng)是一個(gè) 可監(jiān)聽(tīng)對(duì)象(observable)赖条,有些像是一個(gè)迭代器和promise的組合失乾。就目前來(lái)說(shuō),我們不會(huì)進(jìn)一步探討這個(gè)話題纬乍,但是會(huì)繼續(xù)關(guān)注它的演變碱茁。

警告

關(guān)于async function的一個(gè)未解的爭(zhēng)論點(diǎn)是,因?yàn)樗鼉H返回一個(gè)promise仿贬,所以沒(méi)有辦法從外部 撤銷 一個(gè)當(dāng)前正在運(yùn)行的async function實(shí)例纽竣。如果這個(gè)異步操作是資源密集型的,而且你想在自己確定不需要它的結(jié)果時(shí)能立即釋放資源,這可能是一個(gè)問(wèn)題蜓氨。

舉例來(lái)說(shuō):

async function request(url) {
    var resp = await (
        new Promise( function(resolve,reject){
            var xhr = new XMLHttpRequest();
            xhr.open( "GET", url );
            xhr.onreadystatechange = function(){
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) {
                        resolve( xhr );
                    }
                    else {
                        reject( xhr.statusText );
                    }
                }
            };
            xhr.send();
        } )
    );

    return resp.responseText;
}

var pr = request( "http://some.url.1" );

pr.then(
    function fulfilled(responseText){
        // ajax 成功
    },
    function rejected(reason){
        // 噢聋袋,什么東西搞錯(cuò)了
    }
);

我構(gòu)想的request(..)有點(diǎn)兒像最近被提案要包含進(jìn)web平臺(tái)的fetch(..)工具。我們關(guān)心的是穴吹,例如幽勒,如果你想要用pr值以某種方法指示撤銷一個(gè)長(zhǎng)時(shí)間運(yùn)行的Ajax請(qǐng)求會(huì)怎么樣?

Promise是不可撤銷的(在本書(shū)寫(xiě)作時(shí))港令。在我和其他許多人看來(lái)代嗤,它們就不應(yīng)該是可以被撤銷的(參見(jiàn)本系列的 異步與性能)。而且即使一個(gè)proimse確實(shí)擁有一個(gè)cancel()方法缠借,那么一定意味著調(diào)用pr.cancel()應(yīng)當(dāng)真的沿著promise鏈一路傳播一個(gè)撤銷信號(hào)到async function嗎?

對(duì)于這個(gè)爭(zhēng)論的幾種可能的解決方案已經(jīng)浮出水面:

  • async function將根本不能被撤銷(現(xiàn)狀)
  • 一個(gè)“撤銷存根”可以在調(diào)用時(shí)傳遞給一個(gè)異步函數(shù)
  • 將返回值改變?yōu)橐粋€(gè)新增的可撤銷promsie類型
  • 將返回值改變?yōu)榉莗romise的其他東西(比如宜猜,可監(jiān)聽(tīng)對(duì)象泼返,或帶有promise和撤銷能力的控制存根)

在本書(shū)寫(xiě)作時(shí),async function返回普通的promise姨拥,所以完全改變返回值不太可能绅喉。但是現(xiàn)在下定論還是為時(shí)過(guò)早了。讓我們持續(xù)關(guān)注這個(gè)討論吧叫乌。

Object.observe(..)

前端web開(kāi)發(fā)的圣杯之一就是數(shù)據(jù)綁定 —— 監(jiān)聽(tīng)一個(gè)數(shù)據(jù)對(duì)象的更新并同步這個(gè)數(shù)據(jù)的DOM表現(xiàn)形式柴罐。大多數(shù)JS框架都為這些類型的操作提供某種機(jī)制。

在ES6后期憨奸,我們似乎很有可能看到這門語(yǔ)言通過(guò)一個(gè)稱為Object.observe(..)的工具革屠,對(duì)此提供直接的支持。實(shí)質(zhì)上排宰,它的思想是你可以建立監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)一個(gè)對(duì)象的變化似芝,并在一個(gè)變化發(fā)生的任何時(shí)候調(diào)用一個(gè)回調(diào)。例如板甘,你可相應(yīng)地更新DOM党瓮。

你可以監(jiān)聽(tīng)六種類型的變化:

  • add
  • update
  • delete
  • reconfigure
  • setPrototype
  • preventExtensions

默認(rèn)情況下,你將會(huì)收到所有這些類型的變化的通知盐类,但是你可以將它們過(guò)濾為你關(guān)心的那一些寞奸。

考慮如下代碼:

var obj = { a: 1, b: 2 };

Object.observe(
    obj,
    function(changes){
        for (var change of changes) {
            console.log( change );
        }
    },
    [ "add", "update", "delete" ]
);

obj.c = 3;
// { name: "c", object: obj, type: "add" }

obj.a = 42;
// { name: "a", object: obj, type: "update", oldValue: 1 }

delete obj.b;
// { name: "b", object: obj, type: "delete", oldValue: 2 }

除了主要的"add""update"在跳、和"delete"變化類型:

  • "reconfigure"變化事件在對(duì)象的一個(gè)屬性通過(guò)Object.defineProperty(..)而重新配置時(shí)觸發(fā)枪萄,比如改變它的writable屬性。更多信息參見(jiàn)本系列的 this與對(duì)象原型硬毕。

  • "preventExtensions"變化事件在對(duì)象通過(guò)Object.preventExtensions(..)被設(shè)置為不可擴(kuò)展時(shí)觸發(fā)呻引。

    因?yàn)?code>Object.seal(..)和Object.freeze(..)兩者都暗示著Object.preventExtensions(..),所以它們也將觸發(fā)相應(yīng)的變化事件吐咳。另外逻悠,"reconfigure"變化事件也會(huì)為對(duì)象上的每個(gè)屬性被觸發(fā)元践。

  • "setPrototype"變化事件在一個(gè)對(duì)象的[[Prototype]]被改變時(shí)觸發(fā),不論是使用__proto__setter童谒,還是使用Object.setPrototypeOf(..)設(shè)置它单旁。

注意,這些變化事件在會(huì)在變化發(fā)生后立即觸發(fā)饥伊。不要將它們與代理(見(jiàn)第七章)搞混象浑,代理是可以在動(dòng)作發(fā)生之前攔截它們的。對(duì)象監(jiān)聽(tīng)讓你在變化(或一組變化)發(fā)生之后進(jìn)行應(yīng)答琅豆。

自定義變化事件

除了六種內(nèi)建的變化事件類型愉豺,你還可以監(jiān)聽(tīng)并觸發(fā)自定義變化事件。

考慮如下代碼:

function observer(changes){
    for (var change of changes) {
        if (change.type == "recalc") {
            change.object.c =
                change.object.oldValue +
                change.object.a +
                change.object.b;
        }
    }
}

function changeObj(a,b) {
    var notifier = Object.getNotifier( obj );

    obj.a = a * 2;
    obj.b = b * 3;

    // queue up change events into a set
    notifier.notify( {
        type: "recalc",
        name: "c",
        oldValue: obj.c
    } );
}

var obj = { a: 1, b: 2, c: 3 };

Object.observe(
    obj,
    observer,
    ["recalc"]
);

changeObj( 3, 11 );

obj.a;          // 12
obj.b;          // 30
obj.c;          // 3

變化的集合("recalc"自定義事件)為了投遞給監(jiān)聽(tīng)器而被排隊(duì)茫因,但還沒(méi)被投遞蚪拦,這就是為什么obj.c依然是3

默認(rèn)情況下冻押,這些變化將在當(dāng)前事件輪詢(參見(jiàn)本系列的 異步與性能)的末尾被投遞驰贷。如果你想要立即投遞它們,使用Object.deliverChangeRecords(observer)洛巢。一旦這些變化投遞完成括袒,你就可以觀察到obj.c如預(yù)期地更新為:

obj.c;          // 42

在前面的例子中,我們使用變化完成事件的記錄調(diào)用了notifier.notify(..)稿茉。將變化事件的記錄進(jìn)行排隊(duì)的一種替代形式是使用performChange(..)锹锰,它把事件的類型與事件記錄的屬性(通過(guò)一個(gè)函數(shù)回調(diào))分割開(kāi)來(lái)±炜猓考慮如下代碼:

notifier.performChange( "recalc", function(){
    return {
        name: "c",
        // `this` 是被監(jiān)聽(tīng)的對(duì)象
        oldValue: this.c
    };
} );

在特定的環(huán)境下城须,這種關(guān)注點(diǎn)分離可能與你的使用模式匹配的更干凈。

中止監(jiān)聽(tīng)

正如普通的事件監(jiān)聽(tīng)器一樣米苹,你可能希望停止監(jiān)聽(tīng)一個(gè)對(duì)象的變化事件糕伐。為此,你可以使用Object.unobserve(..)蘸嘶。

舉例來(lái)說(shuō):

var obj = { a: 1, b: 2 };

Object.observe( obj, function observer(changes) {
    for (var change of changes) {
        if (change.type == "setPrototype") {
            Object.unobserve(
                change.object, observer
            );
            break;
        }
    }
} );

在這個(gè)小例子中良瞧,我們監(jiān)聽(tīng)變化事件直到我們看到"setPrototype"事件到來(lái),那時(shí)我們就不再監(jiān)聽(tīng)任何變化事件了训唱。

指數(shù)操作符

為了使JavaScript以與Math.pow(..)相同的方式進(jìn)行指數(shù)運(yùn)算褥蚯,有一個(gè)操作符被提出了】鲈觯考慮如下代碼:

var a = 2;

a ** 4;         // Math.pow( a, 4 ) == 16

a **= 3;        // a = Math.pow( a, 3 )
a;              // 8

注意: **實(shí)質(zhì)上在Python赞庶、Ruby、Perl、和其他語(yǔ)言中都與此相同歧强。

對(duì)象屬性與 ...

正如我們?cè)诘诙碌摹疤嗬奖。伲线m”一節(jié)中看到的摊册,...操作符在擴(kuò)散或收集一個(gè)數(shù)組上的工作方式是顯而易見(jiàn)的肤京。但對(duì)象會(huì)怎么樣?

這樣的特性在ES6中被考慮過(guò)茅特,但是被推遲到ES6之后(也就是“ES7”或者“ES2016”或者……)了忘分。這是它在“ES6以后”的時(shí)代中可能的工作方式:

var o1 = { a: 1, b: 2 },
    o2 = { c: 3 },
    o3 = { ...o1, ...o2, d: 4 };

console.log( o3.a, o3.b, o3.c, o3.d );
// 1 2 3 4

...操作符也可能被用于將一個(gè)對(duì)象的被解構(gòu)屬性收集到另一個(gè)對(duì)象:

var o1 = { b: 2, c: 3, d: 4 };
var { b, ...o2 } = o1;

console.log( b, o2.c, o2.d );       // 2 3 4

這里,...o2將被解構(gòu)的cd屬性重新收集到一個(gè)o2對(duì)象中(與o1不同白修,o2沒(méi)有b屬性)妒峦。

重申一下,這些只是正在考慮之中的ES6之后的提案兵睛。但是如果它們能被確定下來(lái)就太酷了舟山。

Array#includes(..)

JS開(kāi)發(fā)者需要執(zhí)行的極其常見(jiàn)的一個(gè)任務(wù)就是在一個(gè)值的數(shù)組中搜索一個(gè)值。完成這項(xiàng)任務(wù)的方式曾經(jīng)總是:

var vals = [ "foo", "bar", 42, "baz" ];

if (vals.indexOf( 42 ) >= 0) {
    // 找到了卤恳!
}

進(jìn)行>= 0檢查是因?yàn)?code>indexOf(..)在找到結(jié)果時(shí)返回一個(gè)0或更大的數(shù)字值,或者在沒(méi)找到結(jié)果時(shí)返回-1寒矿。換句話說(shuō)突琳,我們?cè)谝粋€(gè)布爾值的上下文環(huán)境中使用了一個(gè)返回索引的函數(shù)。而由于-1是truthy而非falsy符相,所以我們不得不手動(dòng)進(jìn)行檢查拆融。

在本系列的 類型與文法 中,我探索了另一種我稍稍偏好的模式:

var vals = [ "foo", "bar", 42, "baz" ];

if (~vals.indexOf( 42 )) {
    // 找到了啊终!
}

這里的~操作符使indexOf(..)的返回值與一個(gè)值的范圍相一致镜豹,這個(gè)范圍可以恰當(dāng)?shù)貜?qiáng)制轉(zhuǎn)換為布爾型。也就是蓝牲,-1產(chǎn)生0(falsy)趟脂,而其余的東西產(chǎn)生非零值(truthy),而這正是我們判定是否找到值的依據(jù)例衍。

雖然我覺(jué)得這是一種改進(jìn)昔期,但有另一些人強(qiáng)烈反對(duì)。然而佛玄,沒(méi)有人會(huì)質(zhì)疑indexOf(..)的檢索邏輯是完美的硼一。例如,在數(shù)組中查找NaN值會(huì)失敗梦抢。

于是一個(gè)提案浮出了水面并得到了大量的支持 —— 增加一個(gè)真正的返回布爾值的數(shù)組檢索方法般贼,稱為includes(..)

var vals = [ "foo", "bar", 42, "baz" ];

if (vals.includes( 42 )) {
    // 找到了!
}

注意: Array#includes(..)使用了將會(huì)找到NaN值的匹配邏輯,但將不會(huì)區(qū)分-00(參見(jiàn)本系列的 類型與文法)哼蛆。如果你在自己的程序中不關(guān)心-0值蕊梧,那么它很可能正是你希望的。如果你 確實(shí) 關(guān)心-0人芽,那么你就需要實(shí)現(xiàn)你自己的檢索邏輯望几,很可能是使用Object.is(..)工具(見(jiàn)六章)。

SIMD

我們?cè)诒鞠盗械?異步與性能 中詳細(xì)講解了一個(gè)指令萤厅,多個(gè)數(shù)據(jù)(SIMD)橄抹,但因?yàn)樗俏磥?lái)JS中下一個(gè)很可能被確定下來(lái)的特性,所以這里簡(jiǎn)要地提一下惕味。

SIMD API 暴露了各種底層(CPU)指令楼誓,它們可以同時(shí)操作一個(gè)以上的數(shù)字值。例如名挥,你可以指定兩個(gè)擁有4個(gè)或8個(gè)數(shù)字的 向量疟羹,然后一次性分別相乘所有元素(數(shù)據(jù)并行機(jī)制!)禀倔。

考慮如下代碼:

var v1 = SIMD.float32x4( 3.14159, 21.0, 32.3, 55.55 );
var v2 = SIMD.float32x4( 2.1, 3.2, 4.3, 5.4 );

SIMD.float32x4.mul( v1, v2 );
// [ 6.597339, 67.2, 138.89, 299.97 ]

SIMD將會(huì)引入mul(..)(乘法)之外的幾種其他操作榄融,比如sub()div()救湖、abs()愧杯、neg()sqrt()鞋既、以及其他許多力九。

并行數(shù)學(xué)操作對(duì)下一代的高性能JS應(yīng)用程序至關(guān)重要。

WebAssembly (WASM)

在本書(shū)的第一版將近完成的時(shí)候邑闺,Brendan Eich 突然宣布了一個(gè)有可能對(duì)JavaScript未來(lái)的道路產(chǎn)生重大沖擊的公告:WebAssembly(WASM)跌前。我們不能在這里詳細(xì)地探討WASM,因?yàn)樵诒緯?shū)寫(xiě)作時(shí)這個(gè)話題為時(shí)過(guò)早了陡舅。但如果不簡(jiǎn)要地提上一句抵乓,這本書(shū)就不夠完整。

JS語(yǔ)言在近期(和近未來(lái)的)設(shè)計(jì)的改變上所承受的最大壓力之一靶衍,就是渴望它能夠成為從其他語(yǔ)言(比如 C/C++医舆,ClojureScript挑随,等等)轉(zhuǎn)譯/交叉編譯來(lái)的、合適的目標(biāo)語(yǔ)言。顯然箫柳,作為JavaScript運(yùn)行的代碼性能是一個(gè)主要問(wèn)題涧团。

正如在本系列的 異步與性能 中討論過(guò)的质涛,幾年前一組在Mozilla的開(kāi)發(fā)者給JavaScript引入了一個(gè)稱為ASM.js的想法阐斜。AMS.js是一個(gè)合法JS的子集皱蹦,它大幅地制約了使代碼難于被JS引擎優(yōu)化的特定行為。其結(jié)果就是兼容AMS.js的代碼在一個(gè)支持ASM的引擎上可以顯著地快速運(yùn)行眷蜈,幾乎可以與優(yōu)化過(guò)的原生C語(yǔ)言的等價(jià)物相媲美沪哺。許多觀點(diǎn)認(rèn)為,對(duì)于那些將要由JavaScript編寫(xiě)的渴求性能的應(yīng)用程序來(lái)說(shuō)酌儒,ASM.js很可能將是它們的基干辜妓。

換言之,在瀏覽器中條條大路通過(guò)JavaScript通向運(yùn)行的代碼忌怎。

直到WASM公告之前籍滴,是這樣的。WASM提供了另一條路線榴啸,讓其他語(yǔ)言不必非得首先通過(guò)JavaScript就能將瀏覽器的運(yùn)行時(shí)環(huán)境作為運(yùn)行的目標(biāo)孽惰。實(shí)質(zhì)上,如果WASM啟用鸥印,JS引擎將會(huì)生長(zhǎng)出額外的能力 —— 執(zhí)行可以被視為有些與字節(jié)碼相似的二進(jìn)制代碼(就像在JVM上運(yùn)行的那些東西)勋功。

WASM提出了一種高度壓縮的代碼AST(語(yǔ)法樹(shù))的二進(jìn)制表示格式,它可以繼而像JS引擎以及它的基礎(chǔ)結(jié)構(gòu)直接發(fā)出指令库说,無(wú)需被JS解析狂鞋,甚至無(wú)需按照J(rèn)S的規(guī)則動(dòng)作。像C或C++這樣的語(yǔ)言可以直接被編譯為WASM格式而非ASM.js潜的,并且由于跳過(guò)JS解析而得到額外的速度優(yōu)勢(shì)骚揍。

短期內(nèi),WASM與AMS.js夏块、JS不相上下。但是最終纤掸,人們預(yù)期WASM將會(huì)生長(zhǎng)出新的能力脐供,那將超過(guò)JS能做的任何事情。例如借跪,讓JS演化出像線程這樣的根本特性 —— 一個(gè)肯定會(huì)對(duì)JS生態(tài)系統(tǒng)造成重大沖擊的改變 —— 作為一個(gè)WASM未來(lái)的擴(kuò)展更有希望政己,也會(huì)緩解改變JS的壓力。

事實(shí)上掏愁,這張新的路線圖為許多語(yǔ)言服務(wù)于web運(yùn)行時(shí)開(kāi)啟了新的道路歇由。對(duì)于web平臺(tái)來(lái)說(shuō),這真是一個(gè)激動(dòng)人心的新路線果港!

它對(duì)JS意味著什么沦泌?JS將會(huì)變得無(wú)關(guān)緊要或者“死去”嗎?絕對(duì)不是辛掠。ASM.js在接下來(lái)的幾年中很可能看不到太多未來(lái)谢谦,但JS在數(shù)量上的絕對(duì)優(yōu)勢(shì)將它安全地錨定在web平臺(tái)中释牺。

WASM的擁護(hù)者們說(shuō),它的成功意味著JS的設(shè)計(jì)將會(huì)被保護(hù)起來(lái)回挽,遠(yuǎn)離那些最終會(huì)迫使它超過(guò)自己合理性的臨界點(diǎn)的壓力没咙。人們估計(jì)WASM將會(huì)成為應(yīng)用程序中高性能部分的首選目標(biāo)語(yǔ)言,這些部分曾用各種各樣不同的語(yǔ)言編寫(xiě)過(guò)千劈。

有趣的是祭刚,JavaScript是未來(lái)不太可能以WASM為目標(biāo)的語(yǔ)言之一∏脚疲可能有一些未來(lái)的改變會(huì)切出JS的一部分涡驮,而使這一部分更適于以WASM作為目標(biāo),但是這件事情看起來(lái)優(yōu)先級(jí)不高憔古。

雖然JS很可能與WASM沒(méi)什么關(guān)聯(lián)遮怜,但JS代碼和WASM代碼將能夠以最重要的方式進(jìn)行交互,就像當(dāng)下的模塊互動(dòng)一樣自然鸿市。你可以想象锯梁,調(diào)用一個(gè)foo()之類的JS函數(shù)而使它實(shí)際上調(diào)用一個(gè)同名WASM函數(shù),它具備遠(yuǎn)離你其余JS的制約而運(yùn)行的能力焰情。

至少是在可預(yù)見(jiàn)的未來(lái)陌凳,當(dāng)下以JS編寫(xiě)的東西可能將繼續(xù)總是由JS編寫(xiě)。轉(zhuǎn)譯為JS的東西將可能最終至少考慮以WASM為目標(biāo)内舟。對(duì)于那些需要極致性能合敦,而且在抽象的層面上沒(méi)有余地的東西,最有可能的選擇是找一種合適的非JS語(yǔ)言編寫(xiě)验游,然后以WASM為目標(biāo)語(yǔ)言充岛。

這個(gè)轉(zhuǎn)變很有可能將會(huì)很慢,會(huì)花上許多年成形耕蝉。WASM在所有的主流瀏覽器上固定下來(lái)可能最快也要花幾年崔梗。同時(shí),WASM項(xiàng)目(https://github.com/WebAssembly)有一個(gè)早期填補(bǔ)垒在,來(lái)為它的基本原則展示概念證明蒜魄。

但隨著時(shí)間的推移,也隨著WASM學(xué)到新的非JS技巧场躯,不難想象一些當(dāng)前是JS的東西被重構(gòu)為以WASM作為目標(biāo)的語(yǔ)言谈为。例如,框架中性能敏感的部分踢关,游戲引擎伞鲫,和其他被深度使用的工具都很可能從這樣的轉(zhuǎn)變中獲益。在web應(yīng)用程序中使用這些工具的開(kāi)發(fā)者們并不會(huì)在使用或整合上注意到太多不同签舞,但確實(shí)會(huì)自動(dòng)地利用這些性能和能力榔昔。

可以確定的是驹闰,隨著WASM變得越來(lái)越真實(shí),它對(duì)JavaScript設(shè)計(jì)路線的影響就越來(lái)越多撒会。這可能是開(kāi)發(fā)者們應(yīng)當(dāng)關(guān)注的最重要的“ES6以后”的話題嘹朗。

復(fù)習(xí)

如果這個(gè)系列的其他書(shū)目實(shí)質(zhì)上提出了這個(gè)挑戰(zhàn),“你(可能)不懂JS(不像自己想象的那么懂)”诵肛,那么這本書(shū)就是在說(shuō)屹培,“你不再懂JS了”。這本書(shū)講解了在ES6中加入到語(yǔ)言里的一大堆新東西怔檩。它是一個(gè)新語(yǔ)言特性的精彩集合褪秀,也是將永遠(yuǎn)改進(jìn)我們JS程序的范例。

但JS不是到ES6就完了薛训!還早得很呢媒吗。已經(jīng)有好幾個(gè)“ES6之后”的特性處于開(kāi)發(fā)的各個(gè)階段。在這一章中乙埃,我們簡(jiǎn)要地看了一些最有可能很快會(huì)被固定在JS中的候選特性闸英。

async function是建立在 generators + promises 模式(見(jiàn)第四章)上的強(qiáng)大語(yǔ)法糖。Object.observe(..)為監(jiān)聽(tīng)對(duì)象變化事件增加了直接原生的支持介袜,它對(duì)實(shí)現(xiàn)數(shù)據(jù)綁定至關(guān)重要甫何。**指數(shù)作符,針對(duì)對(duì)象屬性的...遇伞,以及Array#includes(..)都是對(duì)現(xiàn)存機(jī)制的簡(jiǎn)單而有用的改進(jìn)辙喂。最后,SIMD將高性能JS的演化帶入一個(gè)新紀(jì)元鸠珠。

聽(tīng)起來(lái)很俗套巍耗,但JS的未來(lái)是非常光明的!這個(gè)系列渐排,以及這本書(shū)的挑戰(zhàn)炬太,現(xiàn)在是各位讀者的職責(zé)了。你還在等什么飞盆?是時(shí)候開(kāi)始學(xué)習(xí)和探索了娄琉!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末次乓,一起剝皮案震驚了整個(gè)濱河市吓歇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌票腰,老刑警劉巖城看,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異杏慰,居然都是意外死亡测柠,警方通過(guò)查閱死者的電腦和手機(jī)炼鞠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)轰胁,“玉大人谒主,你說(shuō)我怎么就攤上這事≡叻В” “怎么了霎肯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)榛斯。 經(jīng)常有香客問(wèn)我观游,道長(zhǎng),這世上最難降的妖魔是什么驮俗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任懂缕,我火速辦了婚禮,結(jié)果婚禮上王凑,老公的妹妹穿的比我還像新娘搪柑。我一直安慰自己,他們只是感情好荤崇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布拌屏。 她就那樣靜靜地躺著,像睡著了一般术荤。 火紅的嫁衣襯著肌膚如雪倚喂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天瓣戚,我揣著相機(jī)與錄音端圈,去河邊找鬼。 笑死子库,一個(gè)胖子當(dāng)著我的面吹牛舱权,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仑嗅,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宴倍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了仓技?” 一聲冷哼從身側(cè)響起鸵贬,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脖捻,沒(méi)想到半個(gè)月后阔逼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡地沮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年嗜浮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羡亩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡危融,死狀恐怖畏铆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吉殃,我是刑警寧澤及志,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站寨腔,受9級(jí)特大地震影響速侈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迫卢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一倚搬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乾蛤,春花似錦每界、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至上荡,卻和暖如春趴樱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酪捡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工叁征, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逛薇。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓捺疼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親永罚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啤呼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容