Как клонировать функцию конструктора, чтобы она создавала копию исходного типа, которая ведет себя так же, как оригинал, но имеет свой собственный прототип? - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь полностью клонировать функцию конструктора, чтобы она выполняла в точности то же самое, что и оригинал, но ее прототип настроен на клон оригинала.

Я могу легко клонировать исходный прототип, например, так:

  // the original constructor function is assigned to the `type` variable.

    const prototype = type.prototype;
    const clonePrototype = Object.create(null);
    const props = Object.getOwnPropertyNames(prototype);
    for (let i = 0; i < props.length; ++i) {
        const propertyName = props[i];

        const propDescriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);

        Object.defineProperty(clonePrototype, propertyName,
              Object.getOwnPropertyDescriptor(prototype, propertyName));
    }

Проблема, с которой я сталкиваюсь, заключается в том, как создать функцию-конструктор, у которого свойство prototype установлено для объекта clonePrototype.

Если я это сделаю:

    const newContructor = function() {};
    Object.setPrototypeOf(newContructor, clonePrototype);

, затем newConstructor заканчивается с __proto__, установленным для объекта clonePrototype, и свойством prototype без изменений.Я хотел бы оставить __proto__ без изменений, а prototype установить на новое значение.

Моя цель - клонировать эту функцию конструктора, чтобы она создавала копию исходного типа, которая ведет себя так же, какоригинал, но имеет свой собственный прототип.

Как мне это сделать?

Спасибо!

1 Ответ

0 голосов
/ 06 февраля 2019

Я собираюсь наивно показать вам два решения:

  1. Ответы на ваши вопросы «как» напрямую (по комментариям)
  2. Способ получения результата с помощью JavaScript

Я говорю наивно, потому что, возможно, есть какой-то вариант использования, который требует клонирования (возможно, через некоторое время после того, как прототип Type со временем изменился).Но, учитывая ваши примеры кода, способ JavaScript предполагает неизмененные прототипы.

Итак, вот первый.Обратите внимание на изменения, которые я сделал, чтобы преобразовать выражение функции:

const newContructor = function() {};

В объявление функции:

function NewConstructor() {};

И так как выObject.create это клон, я Object.assign сделаю это по прототипу.

function Type() {};
Type.prototype = {
  a: 1,
  b: 2,
  c: function() {
    console.log(this.a + " + " + this.b + " = " + (this.a + this.b));
  }
}

const prototype = Type.prototype;
const clonePrototype = Object.create(null);
const props = Object.getOwnPropertyNames(prototype);
for (let i = 0; i < props.length; ++i) {
  const propertyName = props[i];
  const propDescriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
  Object.defineProperty(clonePrototype, propertyName,
    Object.getOwnPropertyDescriptor(prototype, propertyName));
}

function NewConstructor() {};
Object.assign(NewConstructor.prototype, clonePrototype);
/********************************************/
let type = new Type();
const cloned = new NewConstructor();

type.c(); // prints 1 + 2 = 3
cloned.c(); // prints 1 + 2 = 3

Object.getPrototypeOf(type).a = 0;
// Alternative syntax that some will dislike and point out it should not be used 
cloned.__proto__.a = 3;

type.c(); // prints 0 + 2 = 2
cloned.c(); // prints 3 + 2 = 5
// Here are the independent prototypes (or type.__proto__ and cloned.__proto__
console.log(Object.getPrototypeOf(type), Object.getPrototypeOf(cloned));

Если прототип является первоначальным прототипом, когда происходит клонирование, гораздо проще использовать прототип в качестве самого конструктора.Это позволяет вам использовать оператор new с вашим прототипом для создания Singleton экземпляра самого прототипа.

В этом примере вы не увидите клонирования прототипа.Для каждого объекта, который нуждается в этом в качестве прототипа, создается одноэлементная версия прототипа.

Затем наблюдается мутация каждого прототипа как независимой друг от друга:

function MyPrototype() {
  this.a = 1;
  this.b = 2;
  this.c = function() {
    console.log(this.a + " + " + this.b + " = " + (this.a + this.b));
  };
}

function Type() {};

function NewConstructor() {};

Type.prototype = new MyPrototype();
NewConstructor.prototype = new MyPrototype();
/********************************************/
let type = new Type();
const cloned = new NewConstructor();

type.c(); // prints 1 + 2 = 3
cloned.c(); // prints 1 + 2 = 3

Object.getPrototypeOf(type).a = 0;
// Alternative syntax that some will dislike and point out it should not be used 
cloned.__proto__.a = 3;

type.c(); // prints 0 + 2 = 2
cloned.c(); // prints 3 + 2 = 5
// Here are the independent prototypes (or type.__proto__ and cloned.__proto__
console.log(Object.getPrototypeOf(type), Object.getPrototypeOf(cloned));
...