为什么 Set 的原型方法在 Object.create(Set.prototype) 上调用时会抛出错误

Why does the prototype methods of Set throw an error when called on Object.create(Set.prototype)

*Chrome 控制台:*

let a = Object.create(Set.prototype);
a instanceof Set    // true
a.add(1);    // Uncaught TypeError: Method Set.prototype.add called on incompatible receiver #<Set>
Set.prototype.add.call(a);    // the same as above

这真是令人困惑。

let a = Object.create(Set.prototype);

Object.create() 方法创建一个具有指定原型对象和属性的新对象。

在我们的例子中,Object.create()创建了一个new Set()的新对象,它将继承Set实例的所有属性和方法。

Set 对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。

在参数的帮助下Set.prototype您可以使用构造函数的原型对象向所有 Set 实例添加属性或方法。

a instanceof Set

它确认实例 aSet 对象的实例,在我们的例子中是的。

a.add(1);

a 对象没有方法 add()

你调用的方法没有实现

Set.prototype.add() or
a.add()

在这两种情况下,您可以尝试通过对象实例 a 调用 add() 方法,而 a 对象没有 add() 方法。

add() 方法与 Set Class.

有关
var oSet = new Set();
var CustomSet = Object.create(oSet);
console.log(CustomSet.__proto__.add(10));

当您在控制台中 运行 以上代码时,您会看到它会在集合中推送值 10。

__proto__ 是查找链中用于解析方法等的实际对象。

prototype 是当你用 new

创建对象时用来构建 __proto__ 的对象

因此原型在实例本身(或其他对象)上不可用,而仅在构造函数上可用。

简而言之:你不能这样做,因为规范说你不能。

参见 Set.prototype.add 的第 3 步:

If S does not have a [[SetData]] internal slot, throw a TypeError exception.

此限​​制的原因是 Set 方法需要它们正在操作的对象中的特定内部状态。拥有正确的原型是不够的;您还必须为您的对象调用 Set 构造函数,这将创建这些内部字段。

我猜你想做的是 class 内置 Set。正如规范还指出的那样,使用 ES6 class 语法很容易实现:

class MySet extends Set {}
var s = new MySet();
s.add(1);

另见这个问题:Inheriting from Set.prototype