Наследование JavaScript: Object.create vs new
В JavaScript какая разница между этими двумя примерами:
Необходимое условие:
function SomeBaseClass(){
}
SomeBaseClass.prototype = {
doThis : function(){
},
doThat : function(){
}
}
Пример наследования A с использованием Object.create:
function MyClass(){
}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
Пример наследования B с использованием нового ключевого слова
function MyClass(){
}
MyClass.prototype = new SomeBaseClass();
Оба примера, похоже, делают то же самое. Когда вы выбрали один за другим?
Дополнительный вопрос:
Рассмотрим код в ссылке ниже (строка 15), где ссылка на собственный конструктор функции хранится в прототипе. Почему это полезно?
https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js
Выдержка (если вы не хотите открывать ссылку):
THREE.ImageLoader.prototype = {
constructor: THREE.ImageLoader
}
Ответы
Ответ 1
В вашем вопросе вы упомянули, что Both examples seem to do the same thing
, Это не совсем так, потому что
Ваш первый пример
function SomeBaseClass(){...}
SomeBaseClass.prototype = {
doThis : function(){...},
doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
В этом примере вы просто наследуете SomeBaseClass' prototype
, но что, если у вас есть свойство в SomeBaseClass
как
function SomeBaseClass(){
this.publicProperty='SomeValue';
}
и если вы используете его как
var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);
Объект obj
не будет иметь свойство publicProperty
, например в этом примере.
Ваш второй пример
MyClass.prototype = new SomeBaseClass();
Выполняет функцию constructor
, создавая экземпляр SomeBaseClass
и наследуя весь объект SomeBaseClass
. Итак, если вы используете
var obj=new MyClass();
console.log(obj.publicProperty); // SomeValue
console.log(obj);
В этом случае его свойство publicProperty
также доступно для объекта obj
, такого как в этом примере.
Так как Object.create
недоступен в некоторых старых браузерах, в этом случае вы можете использовать
if(!Object.create)
{
Object.create=function(o){
function F(){}
F.prototype=o;
return new F();
}
}
Выше кода просто добавляет функцию Object.create
, если она недоступна, поэтому вы можете использовать функцию Object.create
, и я думаю, что приведенный выше код описывает, что действительно делает Object.create
. Надеюсь, это поможет в некотором роде.
Ответ 2
Оба примера, похоже, делают то же самое.
Это верно в вашем случае.
Когда вы выбрали один за другим?
Когда SomeBaseClass
имеет тело функции, это будет выполняться с ключевым словом new
. Обычно это не предназначено - вы хотите настроить цепочку прототипов. В некоторых случаях это может вызвать серьезные проблемы, поскольку вы фактически создаете экземпляр объекта, чьи переменные с частным окружением разделяются всеми экземплярами MyClass
, поскольку они наследуют одни и те же привилегированные методы. Возможны другие побочные эффекты.
Итак, вы обычно предпочитаете Object.create
. Тем не менее, он не поддерживается в некоторых устаревших браузерах; что является причиной того, что вы слишком часто наблюдаете new
-approach, так как часто не наносит (очевидного) вреда. Также посмотрите этот ответ.
Ответ 3
Разница становится очевидной, если вы используете Object.create()
по своему усмотрению. Фактически, он полностью скрывает слово prototype
от вашего кода, он выполнит эту работу под капотом. Используя Object.create()
, мы можем пойти как
var base = {
doThis : function(){
},
doThat : function(){
}
};
И тогда мы можем расширять/наследовать другие объекты из этого
var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally
Итак, это еще одна концепция, более "объектно-ориентированный" способ наследования. Например, нет функции "конструктора", используя Object.create()
. Но, конечно же, вы могли бы просто создать и вызвать функцию self defined constructor внутри этих объектов.
Один аргумент для использования Object.create()
заключается в том, что было бы более естественно смешивать /* наследовать * от других объектов, чем использовать способ по умолчанию Javascripts.
Ответ 4
Я не эксперт в java script, но вот простой пример, чтобы понять разницу между "Object.create" и "new"..
шаг 1: создать родительскую функцию с некоторыми свойствами и действиями.
function Person() {
this.name = 'venkat';
this.address = 'dallas';
this.mobile='xxxxxxxxxx'
}
Person.prototype.func1 = function () {
return this.name + this.address;
}
Шаг 2: создайте дочернюю функцию (PersonSalary), которая распространяется выше функции Person, используя ключевое слово Новое.
function PersonSalary() {
Person.call(this);
}
PersonSalary.prototype = new Person();
PersonSalary();
Шаг 3: создайте вторую дочернюю функцию (PersonLeaves), которая распространяется выше функции Person, используя ключевое слово Object.create.
function PersonLeaves() {
Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);
PersonLeaves();
//Теперь проверьте прототипы обоих дочерних функций.
PersonSalary.prototype
PersonLeaves.prototype
обе эти дочерние функции свяжутся с прототипом Person (родительской функции) и могут получить доступ к ним, но если вы создадите дочернюю функцию с помощью new, она вернет совершенно новый объект со всеми родительскими свойствами, которые нам не нужны, а также когда вы создаете любой объект или функцию, используя "New", чтобы выполнялась эта родительская функция, которой мы не хотим быть.
Вот выдержки
если вы просто хотите делегировать некоторые методы в родительской функции и не хотите, чтобы новый объект был создан, наилучшим способом является использование Object.create.