我如何以及为啥要编写一个扩展 null 的类?

Posted

技术标签:

【中文标题】我如何以及为啥要编写一个扩展 null 的类?【英文标题】:How and why would I write a class that extends null?我如何以及为什么要编写一个扩展 null 的类? 【发布时间】:2017-05-02 12:47:57 【问题描述】:

在 ES6 中添加的 javascript 的 class syntax 显然使 extend null 合法:

class foo extends null 

一些谷歌搜索显示was suggested on ES Discuss 这样的声明是错误的;然而,其他评论者认为他们是合法的,理由是

有人可能想要创建一个具有 __proto__: null 原型的类

而争论的那一方最终占了上风。

我无法理解这个假设的用例。一方面,虽然这样的类的声明是合法的,但似乎实例化以这种方式声明的类是不合法的。尝试在 Node.js 或 Chrome 中从上面实例化 foo 类会给我一个非常愚蠢的错误

TypeError: function is not a function

虽然在 Firefox 中做同样的事情给了我

TypeError: function () 
 is not a constructor

在类上定义构造函数没有帮助,如 MDN 当前的特性示例所示;如果我尝试实例化这个类:

class bar extends null 
  constructor()

那么 Chrome/Node 告诉我:

ReferenceError: this is not defined

Firefox 告诉我:

ReferenceError: |this| used uninitialized in bar class constructor

这一切的疯狂是什么?为什么这些空扩展类不可实例化?鉴于它们不可实例化,为什么在规范中故意留下创建它们的可能性,以及为什么一些 MDN 作者认为它是noteworthy enough to document?此功能有哪些可能的用例?

【问题讨论】:

constructor 返回Object.create(null) 作为替代。这显然可以让您避免自动调用super。 jsfiddle.net/w7y2mbcd 但是我猜它实际上不是那个类的成员。 也许让它返回Object.create(bar.prototype)。 jsfiddle.net/w7y2mbcd/1 @squint nice - 您的第二条评论提供了一种实际实例化空扩展类的方法,导致对象不具有 Object.prototype 中的任何方法,例如 .toString().isPrototypeOf()。这比我得到的还远,虽然我仍然不太清楚你为什么想要这样一个对象。 我认为有时人们只想要一个干净的物体。这在我们有Map 之前更重要,所以他们会使用Object.create(null) 作为通用映射,它可以保存事先不知道的任意属性,这样您就可以保证任何属性查找都来自与交互对象而不是默认继承。现在似乎不那么重要了,但话又说回来,这里和那里可能有一些用例。虽然不知道它们是什么。 FWIW,spec 表示extends 后面可以跟任何 LeftHandSideExpression,这基本上意味着可以放在 = 左侧的任何内容。这包括foo()null 之类的东西。现在,null = 42;foo() = 42 都没有意义,但它们是有效的并且会引发运行时错误。 OTOH,class Foo extends bar() 有道理。 编辑: 呃,foo() = 42null = 42 似乎是早期错误,几乎就像语法错误:-/ 【参考方案1】:

EDIT(2021 年):TC39,它指定 JavaScript 仍未完全解决它应该如何工作。这需要在浏览器能够始终如一地实现它之前发生。您可以关注here的最新努力。


原答案

实例化这样的类是为了工作; Chrome 和 Firefox 只是有错误。 Here's Chrome 的,here's Firefox 的。它在 Safari 中运行良好(至少在 master 上)。

规范中曾经有一个bug,这使得它们无法实例化,但它已经修复了一段时间。 (有一个相关的 still,但这不是你看到的。)

用例与Object.create(null)的用例大致相同。有时你想要一些不继承自 Object.prototype 的东西。

【讨论】:

假设我想连接每个对象原型,但我用extend nullObject.create(null) 创建的对象原型? 看起来关于extends null 的规范有changed 和Chrome isn't fixing this bug because of it。【参考方案2】:

回答第二部分:

我无法理解这个假设的用例。

这样,您的对象的原型链中就不会有Object.prototype

class Hash extends null 
var o = ;
var hash = new Hash;
o["foo"] = 5;
hash["foo"] = 5;
// both are used as hash maps (or use `Map`).
hash["toString"]; // undefined
o["toString"]; // function

正如我们所知,undefined 实际上不是一个函数。在这种情况下,我们可以创建对象而不必担心对不应该存在的字段的调用。

这是Object.create(null) 的常见模式,在很多代码库中都很常见,包括像 NodeJS 这样的大型代码库。

【讨论】:

以上是关于我如何以及为啥要编写一个扩展 null 的类?的主要内容,如果未能解决你的问题,请参考以下文章

无法将组件添加到扩展 JFrame 的类

为啥要检查 (*argv == NULL)? [复制]

如何对扩展/继承第 3 方类的类进行单元测试

我无法理解错误是啥以及为啥 e.currentTarget.value 为 null

为啥我得到 null 而不是 Map 对象?如何解决这个问题?

我何时以及为啥要在 Swift 中使用协议?