特別說(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”吧寺。你可以在同一段代碼中使用yield
和await
兩者窜管,甚至是在同一個(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)的c
和d
屬性重新收集到一個(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ū)分-0
與0
(參見(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í)和探索了娄琉!