ES6实例化现有实例的派生类

时间:2018-08-26 01:07:11

标签: javascript ecmascript-6

请考虑以下情形:

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时,我该如何实现?

4 个答案:

答案 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的实例,使用AObject.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);