Понимание разницы между Object.create() и новой функцией SomeFunction()
Недавно я наткнулся на метод Object.create()
в JavaScript, и я пытаюсь определить, как он отличается от создания нового экземпляра объекта с помощью new SomeFunction()
, и когда вы захотите использовать один над другим.
Рассмотрим следующий пример:
var test = {
val: 1,
func: function() {
return this.val;
}
};
var testA = Object.create(test);
testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2
console.log('other test');
var otherTest = function() {
this.val = 1;
this.func = function() {
return this.val;
};
};
var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1
console.log(otherTestB.val); // 2
console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2
Ответы
Ответ 1
Объект, используемый в Object.create, фактически формирует прототип нового объекта, где, как и в новой форме Function(), объявленные свойства/функции не образуют прототип.
Да, Object.create
строит объект, который наследует непосредственно от переданного в качестве первого аргумента.
С помощью конструкторских функций вновь созданный объект наследуется от прототипа конструктора, например:
var o = new SomeConstructor();
В приведенном выше примере o
наследуется непосредственно из SomeConstructor.prototype
.
Здесь разница: Object.create
вы можете создать объект, который не наследует ничего, Object.create(null);
, с другой стороны, если вы установите SomeConstructor.prototype = null;
, вновь созданный объект наследует от Object.prototype
.
Вы не можете создавать замыкания с синтаксисом Object.create, как с функциональным синтаксисом. Это логично, учитывая лексическую (vs block) область видимости JavaScript.
Ну, вы можете создать закрытие, например. используя аргумент дескрипторов свойств:
var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
Обратите внимание, что я говорю об этом методе ECaAScript 5th Edition Object.create
, а не обложке Крокфорда.
Этот метод начинает внедряться в последних браузерах, проверьте эту таблицу .
Ответ 2
Очень просто сказано, new X
есть Object.create(X.prototype)
с дополнительным запуском функции constructor
. (И давая constructor
шанс return
фактическому объекту, который должен быть результатом выражения вместо this
.)
Вот оно.:)
Остальные ответы просто сбивают с толку, потому что, по-видимому, никто еще не читал определение new
.;)
Ответ 3
Вот шаги, которые происходят внутри для обоих вызовов:
(Подсказка: единственное различие заключается в шаге 3)
new Test()
:
- создать
new Object()
obj
- установите
obj.__proto__
в Test.prototype
-
return Test.call(obj) || obj;
// normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
- создать
new Object()
obj
- установите
obj.__proto__
в Test.prototype
-
return obj;
Таким образом, в основном Object.create
не выполняет конструктор.
Ответ 4
Позвольте мне попытаться объяснить (подробнее о Блог):
- Когда вы пишете конструктор
Car
var Car = function(){}
, это то, как вещи внутренне:
У нас есть одна {prototype}
скрытая ссылка на Function.prototype
, которая недоступна, и одна prototype
ссылка на Car.prototype
, которая доступна, и имеет фактический constructor
of Car
. И Function.prototype, и Car.prototype имеют скрытые ссылки на Object.prototype
.
-
Когда мы хотим создать два эквивалентных объекта с помощью оператора new
и create
, тогда мы должны сделать это следующим образом: Honda = new Car();
и Maruti = Object.create(Car.prototype)
.
Что происходит?
Honda = new Car();
— Когда вы создаете такой объект, тогда скрытое свойство {prototype}
указывается на Car.prototype
. Итак, здесь {prototype}
объекта Honda всегда будет Car.prototype
— у нас нет возможности изменить свойство {prototype}
объекта. Что делать, если я хочу изменить прототип нашего вновь созданного объекта?
Maruti = Object.create(Car.prototype)
— Когда вы создаете такой объект, у вас есть дополнительная опция для выбора вашего объекта {prototype}
. Если вы хотите Car.prototype как {prototype}
, тогда передайте его как параметр в функции. Если вам не нужен {prototype}
для вашего объекта, вы можете передать null
следующим образом: Maruti = Object.create(null)
.
Заключение — Используя метод Object.create
, вы можете выбрать свой объект {prototype}
. В new Car();
у вас нет этой свободы.
Предпочтительный способ в JavaScript JavaScript:
Предположим, что у нас есть два объекта a
и b
.
var a = new Object();
var b = new Object();
Теперь предположим, что a
имеет некоторые методы, к которым также хочет обращаться b
. Для этого нам требуется наследование объектов (a
должен быть прототипом b
, только если мы хотим получить доступ к этим методам). Если мы проверим прототипы a
и b
, тогда мы узнаем, что они имеют прототип Object.prototype
.
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
Проблема — мы хотим, чтобы объект a
был прототипом b
, но здесь мы создали объект b
с прототипом Object.prototype
.
Решение. В ECMAScript 5 введено Object.create()
, чтобы добиться такого наследования легко. Если мы создадим объект b
следующим образом:
var b = Object.create(a);
то
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
Итак, если вы выполняете объектно-ориентированный скриптинг, то Object.create()
очень полезен для наследования.
Ответ 5
Это:
var foo = new Foo();
и
var foo = Object.create(Foo.prototype);
весьма схожи. Важным отличием является то, что new Foo
фактически запускает код конструктора, тогда как Object.create
не будет выполнять код, например
function Foo() {
alert("This constructor does not run with Object.create");
}
Обратите внимание, что если вы используете двухпараметрическую версию Object.create()
, вы можете сделать гораздо более мощные вещи.
Ответ 6
function Test(){
this.prop1 = 'prop1';
this.prop2 = 'prop2';
this.func1 = function(){
return this.prop1 + this.prop2;
}
};
Test.prototype.protoProp1 = 'protoProp1';
Test.prototype.protoProp2 = 'protoProp2';
var newKeywordTest = new Test();
var objectCreateTest = Object.create(Test.prototype);
/* Object.create */
console.log(objectCreateTest.prop1); // undefined
console.log(objectCreateTest.protoProp1); // protoProp1
console.log(objectCreateTest.__proto__.protoProp1); // protoProp1
/* new */
console.log(newKeywordTest.prop1); // prop1
console.log(newKeywordTest.__proto__.protoProp1); // protoProp1
Резюме:
1) с ключевым словом new
есть две вещи:
a) функция используется как конструктор
b) function.prototype
объект передается в свойство __proto__
или где __proto__
не поддерживается, это второе место, где новый объект ищет свойства
2) с помощью Object.create(obj.prototype)
вы создаете объект (obj.prototype
) и передаете его объекту, на который он ссылается.. с той разницей, что теперь новый объект __proto__
также указывает на obj.prototype(пожалуйста, xj9 для этого)
Ответ 7
Разница заключается в так называемом "псевдоклассическом и прототипном наследовании". Предложение состоит в том, чтобы использовать только один тип в коде, а не смешивать два.
В псевдоклассическом наследовании (с "новым" оператором) представьте, что вы сначала определяете псевдокласс, а затем создаете объекты из этого класса. Например, определите псевдокласс "Человек", а затем создайте "Алису" и "Боб" из "Лица".
В прототипальном наследовании (используя Object.create) вы непосредственно создаете конкретного человека "Алиса", а затем создаете другого человека "Боб", используя "Алису" в качестве прототипа. Здесь нет "класса"; все объекты.
Внутри JavaScript использует "прототипное наследование"; "псевдоклассический" способ - это просто немного сахара.
См. эту ссылку для сравнения двух способов.
Ответ 8
Внутренне Object.create
делает следующее:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
Синтаксис просто убирает иллюзию, что JavaScript использует Classical Inheritance.
Ответ 9
В соответствии с этим ответом и это видео new
ключевое слово does следующее:
-
Создает новый объект.
-
Связывает новый объект с конструкторской функцией (prototype
).
-
Делает переменную point this
для нового объекта.
-
Выполняет конструкторную функцию с использованием нового объекта и неявного выполнения return this
;
-
Назначает имя функции конструктора новому свойству объекта constructor
.
Object.create
выполняет только шаги 1st
и 2nd
!!!