Понимание разницы между 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(){}, это то, как вещи внутренне: A diagram of prototypal chains when creating javascript objects У нас есть одна {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). A diagram of prototypal chains for differing object creation methods Что происходит?

    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!!!