请考虑以下情形:
class A {
constructor() {
this.A = 'A';
}
createB() {
//Create a B instance from this current instance
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
我希望能够创建B
的实例而不必创建A
的新实例,而是使用现有的A
实例。
我的目标是能够通过调用B
中的函数来生成A
实例,但也允许直接创建B
实例并处理构造默认的{{ 1}}。
当A
扩展B
并要求调用A
时,我该如何实现?
答案 0 :(得分:1)
不确定这正是您想要的,但是它是否适用于您的示例:
class A {
constructor() {
this.A = 'A';
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = new B();
Object.assign(fromInstance, base);
console.log(fromInstance);
这是替代解决方案。实际上,这在C#和Java中非常普遍,但是由于JS没有方法重载,因此与上述解决方案相比,这有点麻烦并且不太好:
class A {
constructor(source) {
if(source){
//use properties/stuff from source
this.A=source.A;
}
else{
//only perform initialization if source is not provided
this.A = 'A';
}
}
}
class B extends A {
constructor(source) {
super(source);
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = new B(base);
console.log(fromInstance);
基本上,构造函数有两种版本,一种创建一个全新的对象,另一种几乎复制一个旧对象。
我认为存在一些误解,无论您做什么,B
的每个实例在定义上都是A
的实例。如果要调用super
,则在调用A
的构造函数,从而“实例化” A
。
答案 1 :(得分:0)
如果我理解问题所在,您希望新实例的A
属性反映创建它的实例的A
属性,对吗?您可以在createB
中进行设置,因为它将在A
实例上被调用。这将使B
实例具有遮盖继承的A
class A {
constructor() {
this.A = 'A';
}
createB() {
let b = new B()
b.A = this.A // set to the instances 'A'
return b
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
console.log(fromInstance)
答案 2 :(得分:0)
通用方法可以将 all 个实例属性复制到一个新的B实例中。一种更通用的方法是先将B对象的属性复制到临时存储中,然后再写回它们,这样,如果A和B具有相同的属性名称,则B对象的属性将优先:
class A {
constructor() {
this.A = 'A';
}
createB() {
let b = new B();
let temp = {};
let aProp, bProp;
// save own properties of b
Object.keys( b).forEach( bProp => (temp[bProp]=b[bProp]));
// install own properties of A instance
Object.keys( this).forEach( aProp => ( b[aProp]=this[aProp]));
// write back b properties over A instance properties
Object.keys( temp).forEach( bProp=> (this[bProp]=temp[bProp]));
return b;
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
console.log( "derived.A = %s", derived.A);
console.log( "fromInstance.A = %s", fromInstance.A);
请注意,在JavaScript术语中,避免使用类构造在语法上更加容易,因为您可以更改普通函数的prototype
属性,但不能更改类构造函数。但是,您可能会失去使用B
可靠地标识instanceof B
实例的能力。在CreateB
中使用类表达式存在相同的问题-返回的对象将不会共享相同的Class构造函数。
答案 3 :(得分:0)
只需创建一个B
的实例,使用A
将Object.assign
的当前实例的属性复制到它,然后将其返回:
createB() {
var b = new B();
Object.assign(b, this);
return b;
}
示例:
class A {
constructor() {
this.A = 'A';
}
createB() {
var b = new B();
Object.assign(b, this);
return b;
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
var fromInstance = base.createB();
console.log(fromInstance instanceof B);
console.log(fromInstance.A);