ES6 Создание производного класса от существующего экземпляра - PullRequest
0 голосов
/ 26 августа 2018

Рассмотрим следующий сценарий:

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 напрямую и обрабатывать создание значения по умолчанию A.

Как мне добиться чего-то подобного, когда B расширяет A и требует, чтобы super() был вызван?

Ответы [ 4 ]

0 голосов
/ 26 августа 2018

Просто создайте экземпляр 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);
0 голосов
/ 26 августа 2018

Если я понимаю проблему, вы хотите, чтобы свойство 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)
0 голосов
/ 26 августа 2018

Общий подход может копировать все Свойства экземпляра в новый экземпляр 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 имеет ту же проблему - возвращаемые объекты не будут использовать один и тот же конструктор класса.

0 голосов
/ 26 августа 2018

Не уверен, что это именно то, что вы хотите, но это работает для вашего примера:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...