本文属于乱侃,其中语言可能包含语句不通甚至颠三倒四前后不搭的部分。如引起各位看官的不适请见谅


于是 Array.prototype.flatten 终于变成 Array.prototype.flat 了:https://github.com/tc39/propo...。方法名变成了一个名词或形容词。

我相信这不是标准制定者所情愿的(虽然有人 强行 解释了一下)。万恶之源就是这个叫做 Mootools 的库。我没有用过,但是听说在多年以前的国外被广泛使用。我不想细谈其内部细节,有兴趣的可以看谷歌的这篇博文:https://developers.google.com...

其实类似事情之前就发生过一次。问题出在同一个库身上,相同的解决方案:Array.prototype.contains 最终变成了 Array.prototype.includes

所谓兼容性就是抗历史包袱。如果一个新版本浏览器发布导致用户经常浏览的网站挂掉,他们不会认为这是网站的不对——他们根本不知道类似 Mootools 这种奇葩的存在。他们只知道:我原来用得好好的,怎么升级之后就坏了?从而加固“跟新有风险,升级需谨慎”的印象,甚至形成“升级恐惧症”。

其他语言或多或少都有一些历史包袱,异常沉重的有如 C++,但是这类编译型语言一旦被编译为目标代码,兼容性包袱便转抛给了操作系统。而前端代码不一样,他们被浏览器下载到了客户端解释(或预编译)执行,语言级别的包袱会一直持续下去。语言设计者们已经做过了尝试,比如这个神奇的 'use strict',但是它永远不可能默认开启。

所以 Mootools 那帮人在私自扩展原生对象的原型属性时,有没有想到着可能是一件会阻碍人类文明的发展进程的严重问题呢?


还是补充说明这次 smoothgate 事件的缘由。

Firefox 基于 Array.prototype.flatten 提议(旧版本,现在已经改为 flat)发布了支持该 API 的新版浏览器,导致了至少一个著名站点出现了异常

Firefox 提供的 Array.prototype.flatten 实现并没有 bug,问题在于网站使用的一个叫 Mootools 的库。它提供了自己 非标准的 Array.prototype.flatten 版本实现。

Array.prototype.flatten = /* 非标准实现 */;

Mootools 提供的实现跟标准不同,然而这不是问题所在。Mootools 会强制覆盖浏览器原生的 Array.prototype.flatten 实现,依赖 MootoolsArray.prototype.flatten 实现的网站并不会因为原生版本和 Mootools 版本不一致而产生问题。

然而不幸的是 Mootools 还做了一件恶心的事情:它会把所有自定义的 Array.prototype 下方法实现复制到 Elements.prototype 下(ElementsMootools 提供的自定义 API)。

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

for-in 循环只会遍历 可枚举的(enumerable)的属性,例如 Array.prototype.sortArray.prototype.push 这些原生的方法都是默认不可枚举的(enumerable: false),新的 Array.prototype.flatten 同样如此。Mootools 用自己的实现覆盖了原生的 Array.prototype.flatten,但是并没有改变方法的 enumerable 属性——Array.prototype.flatten 仍然是不可枚举的,导致 Array.prototype.flatten 不会被复制到 Elements.prototype 下。

于是:所有依赖 Elements.prototype.flatten 的代码全部挂掉了。有人在 TC39 的官方 github 仓库发了个 PR 戏谑说建议把 flatten 改名为 smooth,引发大讨论,甚至有人信以为真导致事件越发扩大。于是 Google Update 官博专门发文辟谣。


CarterLi
1.3k 声望102 粉丝