Понимание разницы между Object.create () и новым SomeFunction () - PullRequest
364 голосов
/ 12 ноября 2010

Недавно я наткнулся на метод 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

Обратите внимание, что в обоих случаях наблюдается одинаковое поведение.Мне кажется, что основными различиями между этими двумя сценариями являются:

  • Объект, используемый в Object.create(), фактически формирует прототип нового объекта, тогда как в new Function() из объявленных свойств /функции не образуют прототип.
  • Нельзя создавать замыкания с синтаксисом Object.create(), как с функциональным синтаксисом.Это логично, учитывая объем лексического (против блочного) типа JavaScript.

Правильны ли приведенные выше утверждения?И я что-то упустил?Когда бы вы использовали один поверх другого?

EDIT: ссылка на версию jsfiddle приведенного выше примера кода: http://jsfiddle.net/rZfYL/

Ответы [ 10 ]

383 голосов
/ 30 июля 2013

Проще говоря, new X - это Object.create(X.prototype) с дополнительным запуском функции constructor. (И давая constructor шанс return фактическому объекту, который должен быть результатом выражения вместо this.)

Вот и все. :)

Остальные ответы просто сбивают с толку, потому что, очевидно, никто больше не читает определение new. ;)

234 голосов
/ 12 ноября 2010

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

Да, Object.create создает объект, который наследует непосредственно от объекта, переданного в качестве первого аргумента.

С помощью функций конструктора вновь созданный объект наследует от прототипа конструктора, например ::

var o = new SomeConstructor();

В приведенном выше примере o наследуется непосредственно от SomeConstructor.prototype.

Здесь есть разница: с Object.create вы можете создать объект, который ни от чего не наследует, Object.create(null);, с другой стороны, если вы установите SomeConstructor.prototype = null;, то вновь созданный объект будет наследоваться от Object.prototype .

Вы не можете создавать замыкания с синтаксисом Object.create, как с функциональным синтаксисом. Это логично, учитывая объем лексического (против блочного) типа JavaScript.

Ну, вы можете создавать замыкания, например, используя аргумент дескрипторов свойств:

var o = Object.create({inherited: 1}, {
  foo: {
    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
  }
});

o.foo; // "foobar"

Обратите внимание, что я имею в виду метод ECMAScript 5-е издание Object.create, а не прокладку Крокфорда.

Этот метод начинает реализовываться в последних версиях браузеров, проверьте таблицу совместимости .

196 голосов
/ 30 января 2013

Вот шаги, которые происходят внутри для обоих вызовов:
(Подсказка: единственное отличие заключается в шаге 3)


new Test():

  1. создать new Object() объект
  2. установить obj.__proto__ в Test.prototype
  3. return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value

Object.create( Test.prototype )

  1. создать new Object() obj
  2. установить obj.__proto__ в Test.prototype
  3. return obj;

Так что в основном Object.create невыполнить конструктор.

59 голосов
/ 03 сентября 2014

Позвольте мне попытаться объяснить (подробнее о Блог ):

  1. Когда вы пишете Car конструктор var Car = function(){}, это внутренне так: A diagram of prototypal chains when creating javascript objectsУ нас есть одна {prototype} скрытая ссылка на Function.prototype, которая недоступна, и одна prototype ссылка на Car.prototype, которая доступна и имеет действительную constructor Car.И Function.prototype, и Car.prototype имеют скрытые ссылки на Object.prototype.
  2. Когда мы хотим создать два эквивалентных объекта с помощью оператора 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(); у вас нет этой свободы.

Предпочтительный способ в OO 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() очень полезен для наследования.

41 голосов
/ 21 апреля 2014

Это:

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(), то вы можетегораздо более могущественные вещи.

22 голосов
/ 22 июня 2013

Разница заключается в так называемом «псевдоклассическом и прототипном наследовании».Рекомендуется использовать только один тип в вашем коде, не смешивая их.

В псевдоклассическом наследовании (с оператором "new") представьте, что вы сначала определили псевдокласс, а затем создали объекты из этогоучебный класс.Например, определите псевдокласс "Person", а затем создайте "Alice" и "Bob" из "Person".

В наследовании прототипа (с помощью Object.create) вы непосредственно создаете конкретного человека "«Алиса», а затем создайте еще одного человека «Боб», используя «Алису» в качестве прототипа.Здесь нет «класса»;все являются объектами.

Внутренне JavaScript использует «прототипное наследование»;«псевдоклассический» путь - это просто сахар.

См. эту ссылку для сравнения двух способов.

21 голосов
/ 21 декабря 2013
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 следует отметить две вещи;

а) функция используется в качестве конструктора

b) function.prototype объект передается в свойство __proto__ ... или там, где __proto__ не поддерживается, это второе место, где новый объект ищет свойства

2) с помощью Object.create(obj.prototype) вы создаете объект (obj.prototype) и передаете его намеченному объекту ... с той разницей, что теперь __proto__ нового объекта также указывает на obj.prototype (пожалуйста, укажите xj9 за это)

10 голосов
/ 12 ноября 2010

Внутренне Object.create делает это:

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

Синтаксис просто устраняет иллюзию, что JavaScript использует классическое наследование.

9 голосов
/ 27 июля 2017

Согласно этому ответу и этому видео * ключевое слово new выполняет следующие действия:

  1. Создает новый объект.

  2. Связывает новый объект с функцией конструктора (prototype).

  3. Создает this переменную, указывающую на новый объект.

  4. Выполняет функцию конструктора с использованием нового объекта и неявного выполнения return this;

  5. Назначает имя функции конструктора для свойства нового объекта constructor.

Object.create выполняет только 1st и 2nd шагов !!!

8 голосов
/ 22 марта 2018

Варианты создания объекта.


Вариант 1 : ' new Object () ' -> Конструктор объекта без аргументов.

var p1 = new Object(); // 'new Object()' create and return empty object -> {}

var p2 = new Object(); // 'new Object()' create and return empty object -> {}

console.log(p1); // empty object -> {}

console.log(p2); // empty object -> {}

// p1 and p2 are pointers to different objects
console.log(p1 === p2); // false

console.log(p1.prototype); // undefined

// empty object which is in fact Object.prototype
console.log(p1.__proto__); // {}

// empty object to which p1.__proto__ points
console.log(Object.prototype); // {}

console.log(p1.__proto__ === Object.prototype); // true

// null, which is in fact Object.prototype.__proto__
console.log(p1.__proto__.__proto__); // null

console.log(Object.prototype.__proto__); // null

enter image description here


Вариант 2 : ' новый объект (персона) ' -> Конструктор объекта с аргументом.

const person = {
    name: 'no name',
    lastName: 'no lastName',
    age: -1
}

// 'new Object(person)' return 'person', which is pointer to the object ->
//  -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p1 = new Object(person);

// 'new Object(person)' return 'person', which is pointer to the object ->
//  -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p2 = new Object(person);

// person, p1 and p2 are pointers to the same object
console.log(p1 === p2); // true
console.log(p1 === person); // true
console.log(p2 === person); // true

p1.name = 'John'; // change 'name' by 'p1'
p2.lastName = 'Doe'; // change 'lastName' by 'p2'
person.age = 25; // change 'age' by 'person'

// when print 'p1', 'p2' and 'person', it's the same result,
// because the object they points is the same
console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(person); // { name: 'John', lastName: 'Doe', age: 25 }

enter image description here


Вариант 3.1 : ' Object.create (человек) ».Используйте Object.create с простым объектом 'person'.Object.create (person) создаст (и вернет) новый пустой объект и добавит свойство __proto__ к тому же новому пустому объекту.Это свойство '__proto__' будет указывать на объект 'person'.

const person = {
        name: 'no name',
        lastName: 'no lastName',
        age: -1,
        getInfo: function getName() {
           return `${this.name} ${this.lastName}, ${this.age}!`;
    }
}

var p1 = Object.create(person);

var p2 = Object.create(person);

// 'p1.__proto__' and 'p2.__proto__' points to
// the same object -> 'person'
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(p1.__proto__);
console.log(p2.__proto__);
console.log(p1.__proto__ === p2.__proto__); // true

console.log(person.__proto__); // {}(which is the Object.prototype)

// 'person', 'p1' and 'p2' are different
console.log(p1 === person); // false
console.log(p1 === p2); // false
console.log(p2 === person); // false

// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);

console.log(p1); // empty object - {}

console.log(p2); // empty object - {}

// add properties to object 'p1'
// (properties with the same names like in object 'person')
p1.name = 'John';
p1.lastName = 'Doe';
p1.age = 25;

// add properties to object 'p2'
// (properties with the same names like in object 'person')
p2.name = 'Tom';
p2.lastName = 'Harrison';
p2.age = 38;

// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);

// { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);

// { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);

// use by '__proto__'(link from 'p1' to 'person'),
// person's function 'getInfo'
console.log(p1.getInfo()); // John Doe, 25!

// use by '__proto__'(link from 'p2' to 'person'),
// person's function 'getInfo'
console.log(p2.getInfo()); // Tom Harrison, 38!

enter image description here


Вариант 3.2 :' Object.create (Object.prototype) '.Используйте Object.create со встроенным объектом -> 'Object.prototype'.Object.create (Object.prototype) создаст (и вернет) новый пустой объект и добавит свойство «__proto__» к тому же новому пустому объекту.Это свойство '__proto__' будет указывать на объект 'Object.prototype'.

// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p1' property '__proto__', which is link to 'Object.prototype'
var p1 = Object.create(Object.prototype);

// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p2' property '__proto__', which is link to 'Object.prototype'
var p2 = Object.create(Object.prototype);

console.log(p1); // {}

console.log(p2); // {}

console.log(p1 === p2); // false

console.log(p1.prototype); // undefined

console.log(p2.prototype); // undefined

console.log(p1.__proto__ === Object.prototype); // true

console.log(p2.__proto__ === Object.prototype); // true

enter image description here


Вариант 4 : ' new SomeFunction () '

// 'this' in constructor-function 'Person'
// represents a new instace,
// that will be created by 'new Person(...)'
// and returned implicitly
function Person(name, lastName, age) {

    this.name = name;
    this.lastName = lastName;
    this.age = age;

    //-----------------------------------------------------------------
    // !--- only for demonstration ---
    // if add function 'getInfo' into
    // constructor-function 'Person',
    // then all instances will have a copy of the function 'getInfo'!
    //
    // this.getInfo: function getInfo() {
    //  return this.name + " " + this.lastName + ", " + this.age + "!";
    // }
    //-----------------------------------------------------------------
}

// 'Person.prototype' is an empty object
// (before add function 'getInfo')
console.log(Person.prototype); // Person {}

// With 'getInfo' added to 'Person.prototype',
// instances by their properties '__proto__',
// will have access to the function 'getInfo'.
// With this approach, instances not need
// a copy of the function 'getInfo' for every instance.
Person.prototype.getInfo = function getInfo() {
    return this.name + " " + this.lastName + ", " + this.age + "!";
}

// after function 'getInfo' is added to 'Person.prototype'
console.log(Person.prototype); // Person { getInfo: [Function: getInfo] }

// create instance 'p1'
var p1 = new Person('John', 'Doe', 25);

// create instance 'p2'
var p2 = new Person('Tom', 'Harrison', 38);

// Person { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);

// Person { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);

// 'p1.__proto__' points to 'Person.prototype'
console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] }

// 'p2.__proto__' points to 'Person.prototype'
console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] }

console.log(p1.__proto__ === p2.__proto__); // true

// 'p1' and 'p2' points to different objects(instaces of 'Person')
console.log(p1 === p2); // false

// 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo' 
// and use 'getInfo' with 'p1'-instance's data
console.log(p1.getInfo()); // John Doe, 25!

// 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo' 
// and use 'getInfo' with 'p2'-instance's data
console.log(p2.getInfo()); // Tom Harrison, 38!

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...