原文: #SmooshGate FAQ 做者:Mathias Bynenshtml
一项名为 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 定义了他们本身的非标准版本 Array.prototype.flatten
:浏览器
Array.prototype.flatten = /* non-standard implementation */;
复制代码
MooTools 的 flatten
实现与建议的标准不一样。可是,这并非问题!当浏览器提供了原生的 Array.prototype.flatten
时,MooTools 会覆盖原生实现。这可确保依赖 MooTools 的代码按预期运行,不管原生 flatten
是否可用。到如今为止还挺好!安全
不幸的是,发生了其余事情。MooTools 将其全部自定义数组方法复制到 Elements.prototype
(Elements
是 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 是什么。
或者,咱们能够找到另外一种解决方案,用户能够继续使用网络。
在极少数状况下,能够从网络中删除不良的功能。即便仅仅弄清楚是否能够删除一个功能也是很是棘手的工做,须要大量的遥测来量化有多少网页会改变他们的行为。可是,若是功能足够不安全,对用户有害,或者不多使用,则能够完成此操做。
<applet>
,<keygen>
和 showModalDialog()
都是从 Web 平台成功删除的错误 API 的示例。
修补 MooTools 以便它再也不扩展内置对象是个不错的主意。可是,它并无解决手头的问题。即便 MooTools 发布补丁版本,全部使用它的现有网站也必须更新,这样兼容性问题才能消失。
在理想状况下 MooTools 会发布一个补丁,每一个使用 MooTools 的网站都会在次日神奇地更新。问题解决了,对吧?!
不幸的是,这是不现实的。即便有人以某种方式识别了整套受影响的网站,也能够设法找到每个网站的联系信息,成功地与全部网站全部者联系并说服他们所有执行更新(这可能意味着重构他们的网站完整的代码库),整个过程最多须要几年的时间。
请记住,这些网站不少都是旧的,可能没法维护。即便维护人员仍然在身边,也可能他们不是像您同样的高技能 Web 开发人员。因为网络兼容性问题,咱们不能期望每一个人都去改变他们已经运行了七八年的网站。
JavaScript 语言基于 ECMAScript 标准,TC39 是负责 JavaScript 语言更新发展的委员会
“Smoosh门”事件使得一些人误认为“TC39 想要把 flatten
从新命名为 smoosh
”,但这是一个没有很好沟通的笑话。重命名提案等重大决策不会被轻视,不会被单我的采纳,而且绝对不会在 GitHub 的评论上完成。
TC39 对于功能提案有着清晰得分级过程。ECMAScript 提案及其任何重大变动(包括方法更新)在 TC39 会议期间进行讨论,而且须要整个委员会批准后方可正式提交。在这种状况下 Array.prototype.flatten
提案已经经历了好几个阶段的讨论,一直到 Stage 3,代表该功能已准备好在 Web 浏览器中实现。实施过程当中出现其余规范问题很常见。在这种状况下,最重要的反馈意见是在试图发布它以后才有的:该特性在当前状态下打破了 Web。即便浏览器发布新功能后 TC39 的流程并无结束,就是由于这些难以预测的问题。
TC39 以协商一致的方式运做,这意味着委员会必须就职何新的变化达成一致。即便 smoosh
是一个严肃的建议,委员会成员彷佛也可能会反对,而是同意使用更常见的名称,例如 compact
或 chain
。
把 flatten
重命名为 smoosh
(即便它不是一个笑话)从未在 TC39 会议上讨论。所以,关于这个问题的官方 TC39 立场目前是未知的。在下次会议达成共识以前,没有任何一我的能够表明全部 TC39 发言。
TC39 会议一般由具备高度多样化背景的人士出席:一些人拥有多年的编程语言设计经验,另外一些人使用浏览器或 JavaScript 引擎工做,愈来愈多的 JavaScript 开发人员社区参与者。
下一次 TC39 会议将于本周举行。议程中有一项讨论 flatten
及其网络兼容性问题。但愿在会议结束后咱们会更多地了解下一步。