ECMAScript 规范是否允许 Array 成为“超类”?

2024-04-23

我正在寻找任何迹象表明“超类化”内置类型是否有效根据规格。也就是说,给定任何假设的 ECMAScript 一致实现,“超类化”内置函数是否会通过影响类构造函数的创建算法来破坏运行时?

“超一流”,我创造的一个术语,指的是一个类,其通过构造它或将其作为函数调用(如果适用)返回的对象将使用相同的内部插槽([[Prototype]] 除外)创建,无论其是什么直接超类是,只要类构造函数的初始[[Prototype]]和类原型在重新分配后仍然位于各自的继承链中。因此,为了成为“超类”,一个类不得致电 super()在创作过程中。

当“超类化”一个Array,我希望它看起来像这样:

// clearly this would break Array if the specification allowed an implementation
// to invoke super() internally in the Array constructor
class Enumerable {
  constructor (iterator = function * () {}) {
    this[Symbol.iterator] = iterator
  }

  asEnumerable() {
    return new Enumerable(this[Symbol.iterator].bind(this))
  }
}

function setSuperclassOf (Class, Superclass) {
  /* These conditions must be satisfied in order to
   * superclass Class with Superclass
   */
  if (
    !(Superclass.prototype instanceof Object.getPrototypeOf(Class.prototype).constructor) ||
    !(Superclass instanceof Object.getPrototypeOf(Class).constructor) ||
     (Superclass.prototype instanceof Class)
  ) {
    throw new TypeError(`${Class.name} cannot have their superclass set to ${Superclass.name}`)
  }
  
  // Now we can superclass Class with Superclass
  Object.setPrototypeOf(Class.prototype, Superclass.prototype)
  Object.setPrototypeOf(Class, Superclass)
}

setSuperclassOf(Array, Enumerable)

const array = new Array(...'abc')

// Checking that Array is not broken by Enumerable
console.log(array[Symbol.iterator] === Array.prototype[Symbol.iterator])

// Checking that Enumerable works as expected
const enumerable = array.asEnumerable()

console.log(array instanceof Enumerable)
console.log(!(enumerable instanceof Array))

for (const letter of enumerable) {
  console.log(letter)
}

我最大的担忧之一是,在内部,在可能一致的实施中,Array could可能看起来像这样,这意味着Array is not“超类”:

class HypotheticalArray extends Object {
  constructor (...values) {
    const [value] = values

    // this reference would be modified by superclassing HypotheticalArray
    super()

    if (values.length === 1) {
      if (typeof value === 'number') {
        if (value !== Math.floor(value) || value < 0) {
          throw new RangeError('Invalid array length')
        }

        this.length = value
        return
      }
    }
    
    this.length = values.length

    for (let i = 0; i < values.length; i++) {
      this[i] = values[i]
    }
  }
  
  * [Symbol.iterator] () {
    const { length } = this

    for (let i = 0; i < length; i++) {
      yield this[i]
    }
  }
}

// Array constructor actually inherits from Function prototype, not Object constructor
Object.setPrototypeOf(HypotheticalArray, Object.getPrototypeOf(Function))

class Enumerable {
  constructor (iterator = function * () {}) {
    this[Symbol.iterator] = iterator
  }

  asEnumerable() {
    return new Enumerable(this[Symbol.iterator].bind(this))
  }
}

function setSuperclassOf (Class, Superclass) {
  /* These conditions must be satisfied in order to
   * superclass Class with Superclass
   */
  if (
    !(Superclass.prototype instanceof Object.getPrototypeOf(Class.prototype).constructor) ||
    !(Superclass instanceof Object.getPrototypeOf(Class).constructor) ||
     (Superclass.prototype instanceof Class)
  ) {
    throw new TypeError(`${Class.name} cannot have their superclass set to ${Superclass.name}`)
  }
  
  // Now we can superclass Class with Superclass
  Object.setPrototypeOf(Class.prototype, Superclass.prototype)
  Object.setPrototypeOf(Class, Superclass)
}

setSuperclassOf(HypotheticalArray, Enumerable)

const array = new HypotheticalArray(...'abc')

// Array is broken by Enumerable
console.log(array[Symbol.iterator] === HypotheticalArray.prototype[Symbol.iterator])

// Checking if Enumerable works as expected
const enumerable = array.asEnumerable()

console.log(array instanceof Enumerable)
console.log(!(enumerable instanceof HypotheticalArray))

// Iteration does not work as expected
for (const letter of enumerable) {
  console.log(letter)
}

然而,Array is如果需要一致的实现,则为“超类”not打电话super():

class HypotheticalArray {
  constructor (...values) {
    const [value] = values

    // doesn't ever invoke the superclass constructor
    // super()

    if (values.length === 1) {
      if (typeof value === 'number') {
        if (value !== Math.floor(value) || value < 0) {
          throw new RangeError('Invalid array length')
        }

        this.length = value
        return
      }
    }
    
    this.length = values.length

    for (let i = 0; i < values.length; i++) {
      this[i] = values[i]
    }
  }
  
  * [Symbol.iterator] () {
    const { length } = this

    for (let i = 0; i < length; i++) {
      yield this[i]
    }
  }
}

class Enumerable {
  constructor (iterator = function * () {}) {
    this[Symbol.iterator] = iterator
  }

  asEnumerable() {
    return new Enumerable(this[Symbol.iterator].bind(this))
  }
}

function setSuperclassOf (Class, Superclass) {
  /* These conditions must be satisfied in order to
   * superclass Class with Superclass
   */
  if (
    !(Superclass.prototype instanceof Object.getPrototypeOf(Class.prototype).constructor) ||
    !(Superclass instanceof Object.getPrototypeOf(Class).constructor) ||
     (Superclass.prototype instanceof Class)
  ) {
    throw new TypeError(`${Class.name} cannot have their superclass set to ${Superclass.name}`)
  }
  
  // Now we can superclass Class with Superclass
  Object.setPrototypeOf(Class.prototype, Superclass.prototype)
  Object.setPrototypeOf(Class, Superclass)
}

setSuperclassOf(HypotheticalArray, Enumerable)

const array = new HypotheticalArray(...'abc')

// Array is not broken by Enumerable
console.log(array[Symbol.iterator] === HypotheticalArray.prototype[Symbol.iterator])

// Checking if Enumerable works as expected
const enumerable = array.asEnumerable()

console.log(array instanceof Enumerable)
console.log(!(enumerable instanceof HypotheticalArray))

// Iteration works as expected
for (const letter of enumerable) {
  console.log(letter)
}

考虑到这一点,我想引用当前草案中的几点,ECMAScript 2018 https://www.ecma-international.org/ecma-262/:

§22.1.1 数组构造函数 https://www.ecma-international.org/ecma-262/#sec-array-constructor

数组构造函数:

  • 创建并初始化一个新的 Array 奇异对象当作为构造函数调用时。
  • 被设计为可子类化。它可以用作类定义的扩展子句的值。想要继承异常 Array 行为的子类构造函数必须包含对 Array 构造函数的 super 调用,以初始化作为 Array 异常对象的子类实例。

§22.1.3 数组原型对象的属性 https://www.ecma-international.org/ecma-262/#sec-properties-of-the-array-prototype-object

Array 原型对象有一个 [[Prototype]] 内部槽,其值为内部对象 %ObjectPrototype%。

Array 原型对象被指定为 Array 奇异对象确保与 ECMAScript 2015 规范之前创建的 ECMAScript 代码兼容。

(emphasis added)

我的理解是,一致的实现是not需要内部调用super()Array构造函数以便将实例正确初始化为异国情调的数组,也不需要Object成为的直接超类Array(尽管我对第 22.1.3 节的第一段引用似乎确实暗示了这一点)。

我的问题是,上面的第一个片段是否按照规范工作,或者它只是因为当前现有的实现允许才工作?即是第一个的实施HypotheticalArray不合格?

对于全额赏金奖励,我还想将这个问题应用于String, Set, Map, and TypedArray(我的意思是Object.getPrototypeOf(Uint8Array.prototype).constructor).

我将奖励第一个回答的 500 奖励积分严格地解决了我关于 ECMAScript 2015 及更高版本中上述内置函数“超类化”实践的问题(草案中Object.setPrototypeOf()被介绍)。

我不打算支持 ECMAScript 版本 5.1 及以下版本,因为只能通过访问来修改内置的继承链__proto__,即not部分anyECMAScript 规范因此依赖于实现。

P.S. I am fully aware of the reasons that practices like this are discouraged, which is why I would like to determine if the specification allows for "superclassing" without "breaking the web", as TC39 likes to say.


打电话给你的setSuperclassOf任何 ECMAScript 内置类上的函数都不会影响构造函数的行为。

Your HypotheticalArray构造函数不应该 - 不得 - 调用super()。在规范中,您不应该只看数组构造函数 section https://www.ecma-international.org/ecma-262/#sec-array-constructor其中给出了简短的概述,但也有小节§22.1.1.1Array() https://www.ecma-international.org/ecma-262/#sec-array-constructor-array, §22.1.1.2数组(长度) https://www.ecma-international.org/ecma-262/#sec-array-len and §22.1.1.3数组(...项目) https://www.ecma-international.org/ecma-262/#sec-array-items它给出了当你调用时会发生什么的详细算法Array(作为函数或构造函数)。他们确实查找了原型新目标 https://stackoverflow.com/q/32450516/1048572(像往常一样可以子类化 - 从 ES6 开始),但是他们不查找原型Array函数本身。相反,他们都直接发送到数组创建算法 https://www.ecma-international.org/ecma-262/#sec-arraycreate,它只是创建一个对象,设置其原型并安装奇异的属性语义。

这类似于String https://www.ecma-international.org/ecma-262/#sec-string-constructor-string-value(它发送到字符串创建算法 https://www.ecma-international.org/ecma-262/#sec-stringcreate当作为构造函数调用时),抽象的TypedArray构造函数 https://www.ecma-international.org/ecma-262/#sec-%typedarray%(它只是抛出并明确指出“TypedArray 构造函数不会对其执行 super 调用。"), the 具体的 TypedArray 构造函数 https://www.ecma-international.org/ecma-262/#sec-typedarray-constructors(发送到分配类型化数组 https://www.ecma-international.org/ecma-262/#sec-allocatetypedarray and 整数索引对象创建 https://www.ecma-international.org/ecma-262/#sec-integerindexedobjectcreate算法),以及Map https://www.ecma-international.org/ecma-262/#sec-map-iterable and Set https://www.ecma-international.org/ecma-262/#sec-set-iterable构造函数(都分派给普通CreateFrom构造函数 https://www.ecma-international.org/ecma-262/#sec-ordinarycreatefromconstructor and 对象创建 https://www.ecma-international.org/ecma-262/#sec-objectcreate算法)。而且据我所知,对于所有其他内置构造函数来说也是一样的,尽管我没有单独检查它们,但从 ES8 开始,它们就太多了。

我的理解是因为Array.prototype本身是一个 Array 外来对象,内部调用不需要兼容的实现super()Array构造函数,以便将实例正确初始化为异国情调的数组

不,这与此无关。一个对象不会因为继承自一个外来对象而变得外来。一个对象是奇异的,因为它是专门创建的。的价值Array.prototype可以是任何东西,它与数组实例的创建无关 - 除此之外它将被用作原型new Array被称为(与new ArraySubclass).

关于Object.setPrototypeOf(Array.prototype, …),请注意Array.prototype甚至不是一个不可变原型外来对象 https://stackoverflow.com/q/41076421/1048572 like Object.prototype,所以是的,您可以这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ECMAScript 规范是否允许 Array 成为“超类”? 的相关文章

  • 从 JavaScript 中 Firebase 数据库的查询结果中获取特定子项的值

    我在 Firebase 上有这个示例数据库 样本数据库 我有一个index html 其中有这两个输入文本 div class login form h2 Login Form h2 div
  • 为具有可变内容的内联块元素提供相同的高度?

    我有 4 个宽度固定但内容可变的内联块元素 并且我希望所有这些元素具有相同的高度 最大元素的高度 请参见这个jsfiddle http jsfiddle net kKZXj 我应该如何实现这个目标 如果仅使用 css 无法做到这一点 那么使
  • 如何使用 JqGrid 子网格进行内联编辑?

    我知道如何使用主网格进行内联编辑 但是有没有办法对子网格进行内联编辑 这是我的 JS 文件 function var lastsel list jqGrid url example php postData q 1 datatype jso
  • 了解执行模型和事件循环

    我读过很多关于JavaScript单线程执行模型 事件循环和事件队列的文章 但有一件事尚不清楚 我创建了一个小提琴来说明我的问题 http jsfiddle net yzpmf67f http jsfiddle net yzpmf67f
  • Jquery 动画与 CSS 浮动

    我的代码有问题 宽度似乎可以工作 但浮动没有 这里是 这是一个例子 http jsfiddle net v82ck http jsfiddle net v82ck 问题 悬停时菜单上的浮动属性不会改变 我希望每个菜单元素下方的线在悬停该菜单
  • Atom“自动完成”不起作用

    因此 当您安装 Atom 时 autocomplete 会随其一起提供 并且默认情况下处于启用状态 当我编写代码时 什么也没有显示 为什么 是否需要配置任何文件才能正常工作 In autocomplete plus settings pag
  • JavaScript 中的常用数字

    在我的任务中 我必须编写一个程序来查找数组中最常见的数字以及它重复的次数 我写了一些东西 但只打印最大重复次数 所以我的问题是如何打印这个元素的值 最大数量 在我的例子中是 4 var array 13 4 1 1 4 2 3 4 4 1
  • 是否可以用 json 进行表达式/计算?

    我使用出色的 json server 作为应用程序的后端 它对于访问自定义端点以检索一些数据非常有用 但是如果它允许我进行计算 表达式以便我也可以模仿后端行为 那将会非常有用 以这个数据结构为例 products name football
  • GeoJSON 要素坐标未显示在 OpenLayers 地图上

    我正在尝试显示一个GeoJSON地图上的多边形 我使用了 OpenLayers 提供的示例以及以下数据 但仅显示第二个多边形 var geojsonObject type FeatureCollection crs type name fe
  • 嵌套对象的 AJV 模式验证

    函数返回的对象看起来像这样 answer vehicle type 1 message Car model VW color red 答案 对象始终存在 其他字段基于 vehicle type E g 如果vehicle type 1 则有
  • 向 FTP 服务器执行跨域 XMLHTTPREQUEST 的语法是什么?

    我有一个 webDav CORS 插件 可以使用它在 webDav 服务器上 POST PUT GET REMOVE ALLDOCS 文件 我现在想对 FTP 做同样的事情 但我正在努力获取xmlhttprequest 工作语法 我只是收到
  • Backbone-relational 无法实例化两个 RelationalModel 对象

    我正在尝试实现 BackboneRelational 并不断获得 无法实例化多个 Backbone RelationalModel 每种类型都有相同的 ID class App Models User extends Backbone Re
  • 使用JS将图像的特定背景颜色设置为透明

    我正在使用以下代码来修改图像的透明度 然而 我想做的只是修改图像的背景颜色并将其 alpha 通道设置为 0 而不是整个图像 以下代码将整个图像的 Alpha 透明度设置为 0 var ctx this data getContext 2d
  • 指向字节数组的指针

    由于 Misra C 的要求 我的一位同事想要使用指针声明 但我遇到了一些问题 Misra 安全关键指南 不会让我们纯粹的程序员使用指针 但会让我们对数组字节进行操作 他打算获取一个指向字节数组的指针 因此我们不会在堆栈上传递实际的数组 T
  • Crystal Report:如何计算一个公式中的多个 IF 语句?

    背景 我正在尝试对报告的详细信息行进行一些美观的验证 我有几个名为 Assert 语句的公式 如果测试失败则返回 false 如果通过则返回 true Goal 我想创建一个存储 违反规则 的数组 然后将它们显示在行末尾的字段中 标题为 违
  • 单击窗口后才检测到 keydown

    在我的 Web 应用程序中 我有一个用于打开菜单的键的事件侦听器 仅当我单击页面上的任意位置后 此功能才可以正常工作 我尝试将焦点添加到窗口加载 但这仍然不会让 keydown 函数运行 直到我单击页面上的某个位置之后 有谁知道这是否可能
  • ERR_IMPORT_ASSERTION_TYPE_MISSING 用于导入 json 文件

    这段代码运行良好 我不知道是因为我升级到 Node 17 还是什么原因 但现在我明白了 TypeError ERR IMPORT ASSERTION TYPE MISSING Module file Users xxxxx code pro
  • 将 javascript 变量发送到服务器端 ASP .NET

    我需要在回发时将 JavaScript 数据传递到服务器端 Exvar jsVariableToPass new Object jsVariableToPass key1 value1 jsVariableToPass key2 value
  • 可选链接在 create-react-app 中不起作用

    In a create react app项目 我正在使用 babel plugin proposal optional chaining在我的 babelrc中 但是 我有这个错误 Module parse failed Unexpect
  • 如何在 Javascript 中将字符串数组转换为特定的树结构

    我从后端获取文件路径列表 它代表文件夹结构 如下所示 paths path to file1 doc path to file2 doc foo bar doc 路径的长度是任意的 为了使用文件树组件 角度2树组件 https github

随机推荐

  • 查找商店的根类别

    我正在使用 Magento 1 6 1 版 我需要获取商店的根类别 我在谷歌中搜索没有得到任何好的想法 代码 请问如何获取商店的根类别 Mage app gt getStore gt getRootCategoryId 上面的代码给出了默认
  • QList、QVector 或 std::vector 多线程使用

    我希望两个线程像这样工作 第一个线程会将值附加到向量 第二个线程将通过索引对元素进行只读访问 我可以在第二个线程开始读取之前创建互斥体并进行深度复制 但是这种方式真的很慢 如何在没有互斥体的情况下进行此操作 这里 STL向量和线程安全 ht
  • 如何让 Scala ToolBox 查看 REPL 定义?

    当反思还处于萌芽阶段时 在 Scala 2 10 0 里程碑的日子里 我问了一个问题 https stackoverflow com q 11055210 53013关于如何使用它来查看 REPL 中的代码片段树 这个优秀的答案比我问的更进
  • Mvvm Light 和 Visual C# Express?

    MVVM Light 可以与 Visual C Express 一起使用吗 似乎无法显示任何模板 目前 我不支持 MVVM Light 模板的 Visual C Express 我仅支持 Windows Phone 和 Windows 8
  • 当模型中的属性发生更改时收到通知

    对于是否INotifyPropertyChanged是否应该在模型中实现 我认为它应该在 ViewModel 中实现 但我不知道它是如何实现的 stackoverlow com 上到处都提到了同样的想法 在 MVVM 模型中 模型应该实现
  • 提供 REST Web 服务的 JEE6 企业应用程序应该如何组织?

    从一个月前开始 我正在努力学习宁静的网络服务 现在我已经练习了语法并且理解了概念 我决定制作一个非常简单的企业应用程序 其中包括 EJB JPA 和 REST 我正在付出巨大的努力来尝试了解组织这种系统的最佳方式是什么 如果在该领域有经验的
  • Haskell 重叠/不连贯的实例

    我知道这段代码有点傻 但有人可以解释为什么吗isList 42 回报True然而isList2 42 prints False 以及如何防止这种情况发生 我想更好地理解一些更晦涩的 GHC 类型扩展 我认为这将是一个有趣的例子 LANGUA
  • 如何通过单击使 java Module JAR 执行

    我在 Windows 7 上使用 OpenJDK 11 和 OpenJFX 11 我的 IDE 是 Netbeans 9 我复制了以下教程 由 NetbeansVideos 发布 JDK 11 OpenJFX Apache Ant 和 Ap
  • Angular 7 - 浏览器刷新始终重定向到主页

    浏览器刷新后将用户保留在同一页面上的最佳方法是什么 Example 用户位于www domain com page1 http www domain com page1 当他刷新浏览器时 路由器重定向到www domain com home
  • PHP“记住我”安全漏洞?

    我正在编写一个配备 记住我 的登录表单 到目前为止 我读过的教程 部分是为了确保我做得正确 都说将加密的密码存储在 cookie 中与用户名 然后 每次 PHP 检查当前用户是否未登录时 检查他们的 cookie 并查找这些值 如果用户名与
  • 使用 pandas.read_json 时出现 ValueError

    我制作了一个 250MB 的 json 文件 应如下所示 A uniquevalue0 B 1 2 3 A uniquevalue1 B 1 A uniquevalue2 B 1 2 3 4 其中 B 值可以是变量 len gt 1 Thi
  • 在没有实际的 SQL Server 数据库启动和运行的情况下,我将如何配置工作量测试工具来模拟实体框架的 DbContext?

    我们团队的应用程序开发涉及使用工作量测试工具来模拟我们的实体框架的 DbContext 然而 工作量测试工具似乎需要查看应用程序使用的实际 SQL Server 数据库 以便模拟我们的实体框架的 DbContext 这似乎违反了正确的单元测
  • 如何在结构上使用 offsetof() ?

    我想要 offsetof 参数行mystruct1 我试过了 offsetof struct mystruct1 rec structPtr1 u line line and also offsetof struct mystruct1 l
  • 使用 asp.net core 删除所需的验证

    我有一个客户需要表单上有两个按钮 保存未完成表格进度的表格 因此 此表单仍然需要验证字段 但会忽略所需的验证 另一个按钮将需要运行包含必填字段的完整验证 我正在使用库存标准 asp net core 项目 我相信该项目使用 jquery v
  • IE 不会在使用 window.open 创建的窗口中加载 PDF

    问题就在这里 仅发生在 Internet Explorer IE 中 我有一个页面 其中包含指向几种不同类型文件的链接 这些文件中的链接执行一个 Javascript 函数 该函数打开一个新窗口并加载特定文件 这非常有效 除非我需要在新窗口
  • onProviderEnabled 不起作用?

    为了在 GPS 和网络位置提供商之间切换 我只是尝试了这样的方式 以确定何时禁用一个提供商 切换到另一个提供商 但是我的onProviderEnabled 没有被调用 public void onProviderDisabled Strin
  • 正则表达式时区

    我需要一个有效时区的正则表达式 尝试了以下一个 但我不确定 请帮我找出以下正则表达式中的错误 Edited 这里冒号和分钟是可选的 我怎样才能将其更改为强制 如果没有分钟 用户应输入 00 05 00 请帮我解决这个问题 var chkzo
  • 如何将 Git 补丁应用到具有不同名称和路径的文件?

    我有两个存储库 其中 我对文件进行了更改 hello test 我提交更改并从该提交创建补丁git format patch 1 HEAD 现在 我有第二个存储库 其中包含一个与 hello test 内容相同的文件 但以不同的名称放置在不
  • 具有颜色渐变的 3D 散点图,其中颜色取决于计数

    我有一个包含点的数据框 其中包括点的 x y 和 z 坐标以及 计数 每个数据点的数字在 1 到 187 之间 我想将 计数 与颜色渐变相关联 例如1是绿色 187是红色 然后用x y和z坐标绘制数据点的散点图 其中每个数据点的颜色都被编码
  • ECMAScript 规范是否允许 Array 成为“超类”?

    我正在寻找任何迹象表明 超类化 内置类型是否有效根据规格 也就是说 给定任何假设的 ECMAScript 一致实现 超类化 内置函数是否会通过影响类构造函数的创建算法来破坏运行时 超一流 我创造的一个术语 指的是一个类 其通过构造它或将其作