JavaScript 社區由一個庫引起的「smoosh門」事件到底怎麼回事?

原文: #SmooshGate FAQ 做者:Mathias Bynenshtml

smoosh?!發生了什麼?!

一項名爲 JavaScript 功能的提案 Array.prototype.flatten 證實與 Web 不兼容。在 Firefox Nightly 中發佈該功能會致使至少一個受歡迎的網站中斷。鑑於有問題的代碼是普遍使用的 MooTools 庫的一部分,極可能會有更多網站受到影響。(儘管 MooTools 在 2018 年並不經常使用於新網站,但它曾經很是流行,而且仍然存在於許多已經正在運行的網站上。)git

該提案筆者開玩笑地建議flatten 重命名爲 smoosh,以免兼容性問題。github

可是,並不是全部人都知道這是一個笑話,有些人開始錯誤地認爲這個新名字已經被肯定,而且事情迅速升級。web

Array.prototype.flatten 是什麼?

Array.prototype.flatten 遞歸地將數組展按照指定的 depth 進行展平,depth 的默認值爲 1編程

// Flatten one level:
const array = [1, [2, [3]]];
array.flatten();
// → [1, 2, [3]]

// Flatten recursively until the array contains no more nested arrays:
array.flatten(Infinity);
// → [1, 2, 3]
複製代碼

一樣的提議還包括 Array.prototype.flatMap,如同 Array.prototype.map 同樣,能夠在參數裏面傳遞一個回調函數。數組

[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]
複製代碼

MooTools 致使了什麼問題?

MooTools 定義了他們本身的非標準版本 Array.prototype.flatten瀏覽器

Array.prototype.flatten = /* non-standard implementation */;
複製代碼

MooTools 的 flatten 實現與建議的標準不一樣。可是,這並非問題!當瀏覽器提供了原生的 Array.prototype.flatten 時,MooTools 會覆蓋原生實現。這可確保依賴 MooTools 的代碼按預期運行,不管原生 flatten 是否可用。到如今爲止還挺好!安全

不幸的是,發生了其餘事情。MooTools 將其全部自定義數組方法複製到 Elements.prototypeElements 是 MooTools 特定的 API):網絡

for (var key in Array.prototype) {
  Elements.prototype[key] = Array.prototype[key];
}
複製代碼

for-in 遍歷「可枚舉」屬性,其中不包括像原生方法 Array.prototype.sort,而是包括自定義的屬性Array.prototype.foo = whatever。可是 - 背鍋開始了 - 若是你覆蓋了一個非枚舉屬性,例如 Array.prototype.sort = whatever,那麼這個屬性仍然是不可枚舉的。app

目前,Array.prototype.flatten = mooToolsFlattenImplementation 建立一個枚舉 flatten 屬性,因此它之後會被複制到 Elements。可是,若是咱們發佈原生版本的 flatten,它將變得不可枚舉,而且不會被複制到 Elements如今,任何使用 MooTools 並依賴於 Elements.prototype.flatten 的代碼都被破壞了

儘管將原生 Array.prototype.flatten 變爲可枚舉可能會解決問題,但它可能會致使更多的兼容性問題。每一個依賴於 for-in 遍歷數組(這是一個糟糕的作法,但它常常被使用)的網站會忽然獲得該 flatten 屬性的循環迭代。

這裏更大的底層問題是修改內置對象。如今擴展本地原型一般被認爲是一種很差的作法,由於它不能很好地與其餘庫和第三方代碼結合。不要修改不屬於你的對象!

咱們爲何不保留現有名稱並打破網絡?

1996 年,在 CSS 普遍傳播以前,早在「HTML5」以前,Space Jam 網站就已經開始運行了。今天,該網站已經順利運行 22年了。

這是怎麼作到的呢?這些年有沒有人維護該網站,每次瀏覽器供應商發佈新功能時都會更新它?

事實證實,「不要打破網絡」是 HTML,CSS,JavaScript 和 Web 任何標準上都普遍使用的頭號設計原則。若是發佈新的瀏覽器功能致使現有網站中止工做,那對每一個人都不利:

  • 受影響網站的訪問者忽然獲得一個破壞的用戶體驗;

  • 網站全部者從一個完美的網站變成了一個沒有功能的網站,而網站全部者卻並無改變任何東西;

  • 用戶看到「只支持 XXX 瀏覽器」以後切換瀏覽器,所以推出新功能的瀏覽器供應商失去了市場份額。

  • 一旦知道兼容性問題,其餘瀏覽器供應商拒絕實現此特性。致使某特性的規範與實際實現狀況不符(「只是虛構的做品」),這對標準化過程不利。

固然,回想起來 MooTools 作錯了一件事 - 可是打破網絡並不懲罰它們(MooTools),而是會懲罰用戶。這些用戶不知道 MooTools 是什麼。

或者,咱們能夠找到另外一種解決方案,用戶能夠繼續使用網絡。

這是否意味着沒法從 Web 平臺中刪除很差的 API?

在極少數狀況下,能夠從網絡中刪除不良的功能。即便僅僅弄清楚是否能夠刪除一個功能也是很是棘手的工做,須要大量的遙測來量化有多少網頁會改變他們的行爲。可是,若是功能足夠不安全,對用戶有害,或者不多使用,則能夠完成此操做。

<applet><keygen>showModalDialog() 都是從 Web 平臺成功刪除的錯誤 API 的示例。

爲何不修復 MooTools?

修補 MooTools 以便它再也不擴展內置對象是個不錯的主意。可是,它並無解決手頭的問題。即便 MooTools 發佈補丁版本,全部使用它的現有網站也必須更新,這樣兼容性問題才能消失。

能不能只更新網站中使用的 MooTools 副本?

在理想狀況下 MooTools 會發佈一個補丁,每一個使用 MooTools 的網站都會在次日神奇地更新。問題解決了,對吧?!

不幸的是,這是不現實的。即便有人以某種方式識別了整套受影響的網站,也能夠設法找到每個網站的聯繫信息,成功地與全部網站全部者聯繫並說服他們所有執行更新(這可能意味着重構他們的網站完整的代碼庫),整個過程最多須要幾年的時間。

請記住,這些網站不少都是舊的,可​​能沒法維護。即便維護人員仍然在身邊,也可能他們不是像您同樣的高技能 Web 開發人員。因爲網絡兼容性問題,咱們不能期望每一個人都去改變他們已經運行了七八年的網站。

TC39 的工做流程是什麼樣的?

JavaScript 語言基於 ECMAScript 標準,TC39 是負責 JavaScript 語言更新發展的委員會

「Smoosh門」事件使得一些人誤認爲「TC39 想要把 flatten 從新命名爲 smoosh」,但這是一個沒有很好溝通的笑話。重命名提案等重大決策不會被輕視,不會被單我的採納,而且絕對不會在 GitHub 的評論上完成。

TC39 對於功能提案有着清晰得分級過程。ECMAScript 提案及其任何重大變動(包括方法更新)在 TC39 會議期間進行討論,而且須要整個委員會批准後方可正式提交。在這種狀況下 Array.prototype.flatten 提案已經經歷了好幾個階段的討論,一直到 Stage 3,代表該功能已準備好在 Web 瀏覽器中實現。實施過程當中出現其餘規範問題很常見。在這種狀況下,最重要的反饋意見是在試圖發佈它以後纔有的:該特性在當前狀態下打破了 Web。即便瀏覽器發佈新功能後 TC39 的流程並無結束,就是由於這些難以預測的問題。

TC39 以協商一致的方式運做,這意味着委員會必須就職何新的變化達成一致。即便 smoosh 是一個嚴肅的建議,委員會成員彷佛也可能會反對,而是同意使用更常見的名稱,例如 compactchain

flatten 重命名爲 smoosh(即便它不是一個笑話)從未在 TC39 會議上討論。所以,關於這個問題的官方 TC39 立場目前是未知的。在下次會議達成共識以前,沒有任何一我的能夠表明全部 TC39 發言。

TC39 會議一般由具備高度多樣化背景的人士出席:一些人擁有多年的編程語言設計經驗,另外一些人使用瀏覽器或 JavaScript 引擎工做,愈來愈多的 JavaScript 開發人員社區參與者。

接下來發生什麼?

下一次 TC39 會議將於本週舉行。議程中有一項討論 flatten 及其網絡兼容性問題。但願在會議結束後咱們會更多地瞭解下一步。

相關文章
相關標籤/搜索