Понимание создания прототипа объекта с помощью ' Object.create ()' вместо ключевого слова new

Я пришел к коду, который содержит эти строки

var data = function() {
    function Metadata() { /*some initialization here*/ }

    Metadata.prototype = Object.create(Backend.prototype);
    Metadata.prototype.constructor = Metadata;

    return Metadata;
}

Я изо всех сил пытаюсь понять, что на самом деле происходит, и как использовать возвращающийся объект. Если я правильно понял,data теперь будет объект, который должен быть инициализирован такой

var d = new data()

но я не понимаю следующих строк и почему Object.create() вместо new ключевые слова:

Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;

что они делают? Они необходимы? И в чем разница между Object.create и new ?

4 ответов


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

var Data = function() { ... }

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

var data = new Data()

С ECMA Script 6 мы можем использовать метод инстанцирования Object.create(), которые создают неинициированный объект с указанным объектом прототипа и свойствами. Он принимает в аргументе объект, который должен быть прототипом вновь созданного объекта. (Он также копирует конструктор)

таким образом, следующие строки являются способом сделать метаданные, расширяющие бэкэнд-объект и сохраняет свои собственные конструктор:

// Metadata extends Backend
Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;

но этот код не совсем эквивалентно Metadata.prototype = new Backend();. См. этот пример:

//Base class
var Backend = function(){ this.publicProperty='SomeValue'; }

//Extension class 1
var Metadata1 = function() { }
Metadata1.prototype = Object.create(Backend.prototype);
Metadata1.prototype.constructor = Metadata1;

//Extension class 2
var Metadata2 = function() { }
Metadata2.prototype = new Backend();


/*
 *  Then the results are different (see code snippet at the end of this post)
 */
//result1 = 'undefined'
var data1 = new Metadata1();
var result1 = data1.publicProperty;

//result2 = 'SomeValue'
var data2 = new Metadata2();
var result2 = data2.publicProperty;

на самом деле оба очень похожи, главное отличие в том, что new ключевое слово фактически запускает код конструктора, тогда как Object.create не будет выполнять код.

еще одно отличие заключается в том, что с Object.create вы можете создать объект, который не наследует ни от чего (Object.create(null)).
А если у вас Metadata.prototype = null в вновь созданный объект наследуется от Object.prototype


Примечание: в некоторых старых браузерах (IE8 и ниже) вы можете использовать этот эквивалент код Object.create:

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

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

//Base class
var Backend = function(){ this.publicProperty='SomeValue'; }

//Extension class 1
var Metadata1 = function() { }
Metadata1.prototype = Object.create(Backend.prototype);
Metadata1.prototype.constructor = Metadata1;

//Extension class 2
var Metadata2 = function() { }
Metadata2.prototype = new Backend();


//result: 'undefined'
var data1 = new Metadata1();
$("#result1").text("result1: " +  (typeof data1.publicProperty=='undefined' ? 'undefined' : data1.publicProperty));

//result: 'SomeValue'
var data2 = new Metadata2();
$("#result2").text("result2: " +  (typeof data2.publicProperty=='undefined' ? 'undefined' : data2.publicProperty));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result1"></div>
<div id="result2"></div>

эти две линии являются прототипическим способом иметь Metadata расширения Backend.

классы в JavaScript определяются как функции. Если вы определяете prototype в функции вы можете использовать new ключевое слово (или Object.create) для создания экземпляра класса. Функции / свойства, которые находятся в прототипе, будут находиться в новом экземпляре создаваемого класса.

в приведенном выше коде Metadata.prototype устанавливается в экземпляр Backend, so Metadata.prototype наследует вызов методы/свойства Backend.prototype.

вы можете найти больше на наследование и цепочка прототипов.


в JavaScript нет классов, и вместо этого у нас есть конструкторы, которые можно вызвать с помощью new ключевое слово для создания новых объектов, поэтому мы получим то же поведение, что и классы и экземпляры.

и эти две строки используются для выражения наследования и для создания Metadata выходит Backend в строку:

Metadata.prototype = Object.create(Backend.prototype);

определим прототип Metadata, объект, который должен быть прототипом вновь созданный объект.

в этом строка:

Metadata.prototype.constructor = Metadata;

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

и наследование может быть проверено следующим образом:

var meta = new Metadata(); 

console.log('Is meta an instance of Metadata? ' + (meta instanceof Metadata)); // true
console.log('Is meta an instance of Backend? ' + (meta instanceof Backend)); // true

и вы можете найти больше об этом с другим примером в


Object.create является методом ES6, он создает объект с данным объектом в качестве прототипа.

Metadata.prototype = Object.create(Backend.prototype);

таким образом, вышеуказанная строка означает Metadata наследует все свойства и методы от Backend. Это как-то похоже на следующую строку перед ES6:

Metadata.prototype = new Backend();
, Metadata также наследует constructor собственность от Backend:
var metaData = new Metadata();
metaData.constructor; // function Backend()

это выглядит странно, потому что metaData фактически построен с Metadata, так мы исправляем это так:

Metadata.prototype.constructor = Metadata;

var metaData = new Metadata();
metaData.constructor; // function Metadata()

обратите внимание, что это не беспорядок с instanceof оператор:

metaData instanceof Metadata // true
metaData instanceof Backend  // true