如何克隆 Javascript 类
在单元测试期间,我想用一个名为 Bar 的类来模拟 Foo 类。 我必须更改 Foo 类中的属性以进行测试。
这是我尝试的。 它应该打印:
Foo
Bar
class Foo {
id = 'foo'
constructor() {
console.log(this.id)
}
}
const Bar = { ...Foo }
Bar.prototype.id = 'Bar'
new Foo()
new Bar()
但我得到的却是:
error: Uncaught TypeError: Cannot set property 'id' of undefined
我知道我可以通过创建一个新的 Bar extends Foo 类来实现这一点,但是还有其他可能的解决方案吗?
Object Spread
{...o
仅考虑
可枚举
属性。
来自 MDN (重点是我的):
Spread in object literals The Rest/Spread Properties for ECMAScript proposal (ES2018) added spread properties to object literals. It copies own enumerable properties from a provided object onto a new object.
类和函数的
prototype
属性不可枚举。因此,在
const Bar = {...Foo
中,
Bar
将没有
prototype
属性。这就是为什么你会得到
error: Uncaught TypeError: Cannot set property 'id' of undefined
现在,为了让代码更接近你想要的,你可以这样写:
const Bar = {...Foo, prototype: Foo.prototype};
但是,现在
Bar
的行为与
Foo
不同,因为
它的
prototype
属性是可枚举的。
所以我们可以修改它并写成:
const Bar = {...Foo};
Object.defineProperty(Bar, 'prototype', {value: Foo.protoype, enumerable: false});
// `enumerable` defaults to `false` using this API, just being explicit for exposition.
但是,你的下一个语句
new B
仍然会失败,因为
B
仍然不是类对象或函数对象,因此不能与 new 运算符一起使用。
如果没有更多的上下文,很难说出你为什么真正想要这样做。
最直接的方法是编写以下
class Foo {
id = 'Foo';
constructor() {
console.log(this.id);
}
}
class Bar extends Foo {
id = 'Bar';
}
new Foo() // logs 'Foo'
new Bar() // logs 'Bar'
如果您想避免使用继承,还有其他选择,但不清楚哪些是合适的,因为问题缺乏足够的背景来确定这一点。例如,如果您只想模拟通过
new Foo
创建
的对象,那么您可以使用辅助函数简单地模拟它们,该函数只需用测试值覆盖属性,如果您想模拟
Foo
本身,即类对象,那么替代方案会有所不同。
NodeJS 和 Babel 中的实例属性实际上并未设置为原型。它们设置在构造函数中。
检查此内容:
class Foo {
id = 1
}
new Foo().hasOwnProperty('id') // => true
如果属性未在其自身内定义,则对象将仅在其原型上查找该属性,因此覆盖原型将不起作用。
如果您想避免使用
class
语法,您可以执行以下操作:
function Bar() {
const o = new Foo()
o.id = 'bar'
return o
}
new Bar().id // => 'bar'