Чем __proto__ отличается от constructor.prototype? - PullRequest
151 голосов
/ 16 марта 2009
function Gadget(name, color)
{
   this.name = name;
   this.color = color;
}

Gadget.prototype.rating = 3

var newtoy = new Gadget("webcam", "black")

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

Всегда возвращает объект с рейтингом = 3.

Но если я сделаю следующее:

newtoy.__proto__.__proto__.__proto__

Цепочка возвращается null.

Также в Internet Explorer, как проверить нулевое значение, если свойство __proto__ отсутствует?

Ответы [ 7 ]

196 голосов
/ 28 июня 2012

Недавно я пытался обернуть голову вокруг этого и, наконец, придумал эту «карту», ​​которая, я думаю, проливает полный свет на этот вопрос

http://i.stack.imgur.com/KFzI3.png enter image description here

Я знаю, что я не первый, кто придумывает это, но было интереснее выяснить это, чем найти это :-). Во всяком случае, после этого я нашел, например, эта другая диаграмма, которая, я думаю, говорит в основном то же самое:

Макет объекта Javascript

Самым удивительным для меня было обнаружение, что Object.__proto__ указывает на Function.prototype вместо Object.prototype, но я уверен, что для этого есть веская причина: -)

Я вставляю код, указанный на картинке, здесь также, если кто-то хочет его протестировать. Обратите внимание, что некоторые свойства добавлены к объектам, чтобы было легче узнать, где мы находимся после нескольких прыжков:

Object.O1='';
Object.prototype.Op1='';

Function.F1 = '';
Function.prototype.Fp1 = '';

Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';

mycat = new Cat();
o = {};

// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);
66 голосов
/ 16 марта 2009

constructor - это предварительно определенное свойство [[DontEnum]] объекта, на которое указывает свойство prototype объекта функции, и первоначально будет указывать на сам объект функции.

__proto__ эквивалентно внутреннему свойству [[Prototype]] объекта, то есть его фактическому прототипу.

Когда вы создаете объект с оператором new, его внутреннее свойство [[Prototype]] будет установлено на объект, на который указывает свойство prototype функции конструктора.

Это означает, что .constructor будет иметь значение .__proto__.constructor, т.е. функцию конструктора, использованную для создания объекта, и, как мы узнали, свойство protoype этой функции использовалось для установки объекта [[Prototype]. ].

Отсюда следует, что .constructor.prototype.constructor идентичен .constructor (до тех пор, пока эти свойства не были перезаписаны); см. здесь для более подробного объяснения.

Если доступно __proto__, вы можете пройтись по фактической цепочке прототипов объекта. Нет простого способа сделать это в простом ECMAScript3, потому что JavaScript не был разработан для иерархий с глубоким наследованием.

30 голосов
/ 06 февраля 2013

Наследование прототипов в JavaScript основано на свойстве __proto__ в том смысле, что каждый объект наследует содержимое объекта, на которое ссылается его свойство __proto__.

Свойство prototype является специальным только для объектов Function и только при использовании оператора new для вызова Function в качестве конструктора. В этом случае для созданного объекта __proto__ будет установлено значение Function.prototype.

для конструктора.

Это означает, что добавление к Function.prototype автоматически отразится на всех объектах, чья __proto__ ссылается на Function.prototype.

Замена Function.prototype конструктора другим объектом не обновит свойство __proto__ для любого из уже существующих объектов.

Обратите внимание, что свойство __proto__ не должно быть доступно напрямую, вместо него следует использовать Object.getPrototypeOf (object) .

Чтобы ответить на первый вопрос, я создал специальную диаграмму из ссылок __proto__ и prototype, к сожалению, stackoverflow не позволяет мне добавлять изображение с «репутацией менее 10». Может быть, в другой раз.

[Изменить] На рисунке используется [[Prototype]] вместо __proto__, потому что именно так спецификация ECMAScript относится к внутренним объектам. Я надеюсь, что вы можете понять все.

Вот несколько советов, которые помогут вам понять фигуру:

red    = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green  = user-created objects
         (first created using Object constructor or object literal {},
          second using user-defined constructor function)
blue   = user-defined function and its prototype
         (when you create a function, two objects are created in memory:
          the function and its prototype)

Обратите внимание, что свойство constructor не существует в созданных объектах, но наследуется от прототипа.

enter image description here

13 голосов
/ 27 июля 2012

Object - это Ева, а Function - это Адам, Адам (Function) использует свою кость (Function.prototype) для создания Евы (Object). Тогда кто создал Адама (Function)? - Изобретатель языка JavaScript: -).

Согласно ответу Усаины, я хочу добавить больше полезной информации.

Самым удивительным для меня было обнаружение, что Object.__proto__ указывает на Function.prototype вместо Object.prototype, но я уверен, что для этого есть все основания: -)

Этого не должно быть. Object.__proto__ НЕ ДОЛЖЕН указывать на Object.prototype. Вместо этого экземпляр Object o, o.__proto__ должен указывать на Object.prototype.

(Простите за использование терминов class и instance в JavaScript, но вы это знаете: -)

Я думаю, что сам класс Object является экземпляром Function, поэтому Object.__proto__ === Function.prototype. Следовательно: Object - это Ева, а Function - это Адам, Адам (Function) использует свою кость (Function.prototype), чтобы создать Еву (Object).

Кроме того, даже сам класс Function является экземпляром самого Function, то есть Function.__proto__ === Function.prototype, поэтому также Function === Function.constructor

Более того, обычный класс Cat является экземпляром Function, то есть Cat.__proto__ === Function.prototype.

Причина вышеизложенного состоит в том, что когда мы создаем класс в JavaScript, фактически мы просто создаем функцию, которая должна быть экземпляром Function. Object и Function - это просто особые, но они все еще классы, в то время как Cat - обычный класс.

Фактически, в движке Google Chrome JavaScript следующие 4:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

Все они === (абсолютно равны) другим 3, и их значение равно function Empty() {}

> Function.prototype
  function Empty() {}
> Function.__proto__
  function Empty() {}
> Object.__proto__
  function Empty() {}
> Cat.__proto__
  function Empty() {}
> Function.prototype === Function.__proto__
  true
> Function.__proto__ === Object.__proto__
  true
> Object.__proto__ === Cat.__proto__
  true

OK. Тогда кто создает специальное function Empty() {} (Function.prototype)? Подумай об этом: -)

6 голосов
/ 06 июня 2015

Я действительно не знаю, почему люди не исправили вас о том, где на самом деле проблема в вашем понимании.

Это облегчит вам задачу

Итак, давайте посмотрим, что происходит:

var newtoy = new Gadget("webcam", "black")

newtoy 
  .constructor //newtoy's constructor function is newtoy ( the function itself)
    .prototype // the function has a prototype property.( all functions has)
      .constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? )  ! it is not(!) the constructor function  !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
         .prototype // so again we are at line 3 of this code snippet
            .constructor //same as line 4 ...
                .prototype 
                 rating = 3

Отлично, теперь давайте посмотрим на это __proto__

Перед этим, пожалуйста, помните 2 вещи относительно __proto__:

  1. Когда вы создаете объект с оператором new, его внутреннее свойство [[Prototype]] / proto__ будет установлено равным prototype свойству (1) его constructor function или «создателю», если тебе нравится .

  2. Жестко закодировано в JS -: Object.prototype.__proto__ равно null.

Давайте назовем эти 2 пункта "bill"

newtoy
     .__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
       .__proto__ // Ok so now our starting point is `Gadget.prototype`. so  regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`.  Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of   its `constructor function`"
          .__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED

лучше?

2 голосов
/ 29 декабря 2013

Каждая функция создает свой прототип. И когда мы создаем объект с использованием этого конструктора функции, свойство __ proto __ моего объекта начнет указывать на прототип этой функции.

0 голосов
/ 07 июня 2018

Если все эти цифры были ошеломляющими, давайте посмотрим, что означают свойства.

STH.prototype

При создании новой функции параллельно создается пустой объект, связанный с функцией цепочкой [[Prototype]]. Для доступа к этому объекту мы используем prototype свойство функции.

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

Имейте в виду, что свойство prototype доступно только для функций.

STH.constructor

Упомянутый выше объект-прототип не имеет свойств, кроме одного - constructor. Это свойство представляет функцию, которая создала объект-прототип.

var toy = new Gadget();

При создании функции Gadget мы также создали объект, подобный {constructor: Gadget} - это не похоже на Gadget.prototype. Поскольку constructor относится к функции, которая создала прототип объекта, toy.constructor представляет функцию Gadget. Мы пишем toy.constructor.prototype и снова получаем {constructor: Gadget}.

Следовательно, существует замкнутый круг: вы можете использовать toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype, и он всегда будет Gadget.prototype.

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

STH .__ прото __

В то время как prototype является свойством, специфичным для функций, __proto__ доступно для всех объектов, поскольку оно лежит в Object.prototype. Это относится к прототипу функции, которая может создать объект.

[].__proto__ === Array.prototype
// true

({}).__proto === Object.prototype
// true

Здесь toy.__proto__ равно Gadget.prototype. Поскольку Gadget.prototype является объектом ({}) и объекты создаются с помощью функции Object (см. Пример выше), мы получаем Object.prototype. Это более высокий объект в JavaScript, и его __proto__ может указывать только null.

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain
...