Как работает object.create в JavaScript? - PullRequest
18 голосов
/ 01 ноября 2011

Скажите, если я ошибаюсь:

Прототип - это обычный объект.Когда объект наследует прототип, он не просто копирует свойства прототипа, объект хранит ссылку на прототип.

В Firefox я могу сделать:

var food = {fruit:"apple"};
var more_food = {vegetable:"celery"};
food.__proto__ = more_food;
food.vegetable // celery
food.fruit // apple

Iможно использовать свойство __proto__, чтобы вручную установить ссылку на объект-прототип.

Я также могу использовать Object.create:

var food = {fruit:"apple"};
var more_food = {vegetable:"celery"};
food = Object.create(more_food);
food.vegetable // celery
food.fruit // undefined

Что именно делает Object.create?Переменной food присвоена ссылка на прототип more_food, или Object.create просто возвращает копию объекта more_food?Если Object.create просто делает копию, то как работает цепочка прототипов, если переменная food не имеет ссылки на more_food?

1 Ответ

35 голосов
/ 01 ноября 2011

Прототип - это обычный объект.Когда объект наследует прототип, он не просто копирует свойства прототипа, он хранит ссылку на прототип.

Вы правы, прототип объекта - это просто еще одинобъект, на который ссылаются через цепочку прототипов.

Разница между вашими двумя фрагментами в том, что с __proto__ вы мутируете прототип food.Во втором примере вы просто присваиваете новый объект, который наследуется от more_food, поэтому food.fruit разрешается в undefined, потому что ваш исходный объект food является потерянным этим присваиванием .

Что именно делает Object.create?

Object.create создает новый объект , который наследует от объекта, переданного в качестве первого аргумента (это может быть только объект или null).

Переменной food присвоена ссылка на прототип more_food или Object.create просто возвращает копию объекта more_food?

Ваша переменная food будет содержать новый объект, который наследуется от more_food, в этой операции нет никакого копирования.

Например:

var food = {fruit:"apple"};
var more_food = Object.create(food, {
  vegetable: { value: "celery" }
});

more_food.fruit;     // "apple"
more_food.vegetable; // "celery"

В приведенном выше примере more_food наследуется от food, другими словами, food является прототипом more_food, эта прототипная ссылка хранится во внутреннем свойстве под названием [[Prototype]].Второй аргумент Object.create позволяет вам инициализировать свойства этого нового объекта.

Копирование не выполняется, просто делегирование в приведенном выше примере more_food.fruit доступно через цепочку прототипов.процесс поиска свойств действительно прост: если свойство не найдено у объекта, оно рекурсивно просматривается (делегирование!) на прототипе объекта до тех пор, пока не будет найден объект с прототипом null (например, Object.prototype).).

Итак, more_food.fruit является унаследованным свойством:

more_food.hasOwnProperty('fruit'); // false, inherited
'fruit' in more_food;              // true

В то время как vegetable является собственным свойством из more_food:

more_food.hasOwnProperty('vegetable'); // true

Приведенный выше пример выглядит графически так:


  +---------------------+  [[Prototype]]  +---------------+
  | more_food           |+--------------->| food          |
  |---------------------|                 |---------------|
  | vegetable: "celery" |                 | fruit: "apple |
  +---------------------+                 +---------------+

Если Object.create просто делает копию, то как работает цепочка прототипов, если переменная food не имеет ссылки наmore_food?

Object.create не создает копии объектов, он просто устанавливает прототип нового объекта во время его создания.

Имейте в виду, что __proto__ является стандартная функция , и она будет удалена из реализаций в будущем, она уже указана как устарела в Документация Mozilla , основная причина этого, а также почемуязык, возможно, никогда не сможет изменить цепочку прототипов так, как __proto__ позволяет понять, что это вызывает проблемы оптимизации и безопасности на уровне VM и JIT.

...