Понимание создания прототипа объекта с помощью ' 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