Как работает object.create в JavaScript?

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

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

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

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

Я могу использовать свойство __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? Является ли переменная еда назначенной ссылкой на прототип more_food или Object.create просто возвращает копию объекта more_food? Если Object.create просто создает копию, то как работает цепочка прототипов, если переменная пища не имеет ссылки на more_food?

Ответы

Ответ 1

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

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

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

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

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

Является ли переменная еда назначенной ссылкой на прототип 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 просто создает копию, то как работает цепочка прототипов, если переменная пища не имеет ссылки на more_food?

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

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