扩展JavaScript中已定义的类 [英] Extend already defined class in JavaScript
问题描述
在JS中扩展类的传统方式如下:
The traditional way of extending classes in JS is something like this:
// define constructor function
function Fuu(){}
// extend prototype and override prototype's constructor
Fuu.prototype = Object.create(OtherClass.prototype, {
constructor: {
value: Fuu,
enumerable: false,
writable: true,
configurable: true
}
});
然后,然后将所需的方法添加到原型
Then you add the methods you want to the prototype
Fuu.prototype.method = function() {}
就像这样,您有一个扩展另一个功能的函数. JS中继承的一个很好的例子!
And just like that you have a function extending another. A nice example of inheritance in JS!
我的问题是,当子类已经具有带有方法和属性的原型时,如何扩展.我可以尝试使用for in
循环将旧原型的方法复制到新原型,但是这些方法是不可枚举的(类是使用编译器创建的),并且使用getOwnPropertyNames
做某事似乎不正确.有什么建议吗?我可以做些保留原型并将原型添加到原型的事情吗?
My question is how to extend when the sub class already has a prototype with methods and properties. I could try to copy the the methods of the old prototype to the new one using a for in
loop but the methods are non enumerable(class is created with a transpiler) and doing something with getOwnPropertyNames
doesn't seem right. Any suggestion? can I do something like keeping the prototype and adding a prototype to the prototype?
示例
class Fuu {
someMethod(){} // non enumerable method in Fuu's prototype
}
// My first option: (extending this way `someMethod` is lost)
Fuu.protoype = Object.create(HTMLElement.prototype, {//...same as before})
// Option 2: copy methods from old to new prototype
// Option 3: prototype of prototype?
// Fuu.prototype.prototype = Object.create(HTMLElement.prototype, {...})
推荐答案
您想要类似的东西
┌──> Fuu.prototype
instances ──┤
└──> OtherClass.prototype
但这是不可能的,因为对象只有一个[[Prototype]].
But that's not possible, because objects only have one [[Prototype]].
因此,您必须实现以下条件之一:
Therefore, you must achieve one of these:
instances ───> Fuu.prototype ───> OtherClass.prototype
instances ───> OtherClass.prototype ───> Fuu.prototype
因此,您必须将其中一个的[[Prototype]]设置为另一个.我将假设第一种可能性.
So you must set the [[Prototype]] of one of those to be the other one. I will assume the first possibility.
设置[[Prototype]]的主要方法有两种:
There are two main ways to set the [[Prototype]]:
-
Object.create
,在创建对象时
Object.create
, when creating the object
问题在于Fuu.prototype
和OtherClass.prototype
都已经创建.
The problem is that both Fuu.prototype
and OtherClass.prototype
have been created already.
但是,您可以使用右侧的[[Prototype]]创建一个新对象并分配旧对象的属性.
However, you can create a new object with the right [[Prototype]] and assign the properties of the old one.
由于可能存在不可枚举的属性,因此必须使用 getOwnPropertyNames
.使用 defineProperty
和 getOwnPropertyDescriptor
可能也是一个好主意,以防有吸气剂或吸气剂.
Since there may be non-enumerable properties, you must use getOwnPropertyNames
. Using defineProperty
and getOwnPropertyDescriptor
may also be a good idea, in case there are getters or setters.
var old = Fuu.prototype,
props = Object.getOwnPropertyNames(old);
Fuu.prototype = Object.create(OtherClass.prototype);
for(var i=0; i<props.length; ++i)
Object.defineProperty(
Fuu.prototype,
props[i],
Object.getOwnPropertyDescriptor(old, props[i])
);
setPrototypeOf
或 __proto__
( ES6),一旦创建了对象:
setPrototypeOf
or __proto__
(ES6), once the object has been created:
Object.setPrototypeOf(Fuu.prototype, OtherClass.prototype);
Fuu.prototype.__proto__ = OtherClass.prototype;
但是,请注意
根据对象的性质,更改对象的[[Prototype]] 现代的JavaScript引擎优化了属性访问,这非常慢 每个浏览器和JavaScript引擎中的操作.对的影响 变异原型的性能可能会扩展到任何代码, 有权访问其[[Prototype]]已被更改的任何对象.如果你 在乎性能时,您应该避免使[ 一个对象.
Mutating the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of mutating prototypes [...] may extend to any code that has access to any object whose [[Prototype]] has been mutated. If you care about performance you should avoid mutating the [[Prototype]] of an object.
这篇关于扩展JavaScript中已定义的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!