Object.create против прямого прототипного наследования - PullRequest
9 голосов
/ 14 июня 2011

Я играл с Object.create в спецификации EcmaScript 5, и я пытаюсь создать структуру типа множественного наследования.

Скажем, у меня есть несколько функций: a, b и c.Имея дело только с прототипами, я могу сделать это:

function a () {}
a.prototype = {
    fnA = function () {},
    propA = 500
};

function b () {}
b.prototype = a.prototype;
b.prototype.fnB = function () {};
b.prototype.propB = 300;

function c () {}
c.prototype = b.prototype;
c.prototype.fnC = function () {};
c.prototype.propC = 200;

Но используя Object.create, я бы сделал что-то такое:

function a() {}
a.prototype = {
    fnA = function () {},
    propA = 500
};

var b = Object.create(new a());
b.fnB = function () {};
b.propB = 300;

var c = Object.create(b);
c.fnC = function () {};
c.propC = 200;

Я думаю, что получаю одинаковый результат в обоих направлениях.

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

Я что-то упустил?Есть ли какая-то польза от создания Object.create с помощью создания конструкторов?Или это полезно только для копирования существующих объектов?Мне нужен только доступ к свойствам и функциям, прикрепленным к прототипу, а не к функциям и свойствам, добавляемым впоследствии к объекту.

Или как насчет этого (или используйте более глубокое копирование, но идея остается той же)?

function A () {}
A.prototype = {
    fn: function () {
        console.log(this.propA + 30);
    },
    propA: 20
};

function B () {}
Object.keys(A.prototype).forEach(function (item) {
    B.prototype[item] = A.prototype[item];
});
B.prototype.propA = 40;

function C () {}
Object.keys(B.prototype).forEach(function (item) {
    C.prototype[item] = B.prototype[item];
});
C.prototype.fn = function () {
    console.log(this.propA + 3);
};


var a = new A(),
    b = new B(),
    c = new C();

a.fn();
b.fn();
c.fn();

Ответы [ 2 ]

4 голосов
/ 14 июня 2011

На самом деле вы не получаете одинаковый результат в обоих направлениях. Рассмотрим эту строку:

b.prototype = a.prototype;

То, что это делает, устанавливает b.prototype точно такую ​​же ссылку на объект, что и a.prototype. Если вы измените первый объект (скажем, добавив метод fnB), вы также измените второй объект. Это одно и то же. В конце вашего первого набора кода у вас будет три одинаковых прототипа с одинаковыми методами и свойствами.

Весь смысл наследования прототипа заключается в том, что вы определяете «интересный» объект (то есть со всем желаемым поведением), а затем клонируете его с помощью Object.create и изменяете клоны в соответствии с вашими потребностями (обычно путем изменения свойства, а не его методы).

Предположим, у вас есть объект сумматора:

var adder = {x: 0, y: 0};
adder.execute = function () {
  return this.x + this.y;
}

Затем вы создаете клон и задаете его свойства:

var myadder = Object.create(adder);
myadder.x = 1;
myadder.y = 2;
console.log(myadder.execute()); // 3

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

0 голосов
/ 16 ноября 2013

Если вам нужна поддержка браузеров, которые не поддерживают Object.create(), вы можете использовать эту

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

Функция объекта распутывает шаблон конструктора JavaScript, обеспечивая истинное наследование прототипа. Он принимает старый объект в качестве параметра и возвращает пустой новый объект, который наследуется от старого. Если мы попытаемся получить член из нового объекта, и у него нет этого ключа, тогда старый объект предоставит член. Объекты наследуются от объектов. Что может быть более объектно-ориентированным, чем это?

Подробнее можно прочитать здесь: Прототип наследования в JavaScript

...