Чем __proto__ отличается от constructor.prototype?

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__ имущество?

9 ответов

Решение

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

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

Макет объекта 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);

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

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

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

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

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

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

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

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

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

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

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

Чтобы ответить на первый вопрос, я создал диаграмму на заказ __proto__ а также prototype Ссылки, к сожалению, stackru не позволяет мне добавлять изображение с "репутацией менее 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 свойство не существует в созданных объектах, но наследуется от прототипа.

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

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

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

Так не должно быть. Object.__proto__ НЕ должен указывать на Object.prototype, Вместо этого экземпляр Objecto, 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

ХОРОШО. Тогда кто создает специальные function Empty() {} (Function.prototype)? Думаю об этом:-)

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

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

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

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

Лучше?

Короткий ответ: __proto__ это ссылка на prototype свойство конструктора, создавшего объект.

Объекты в JavaScript

Объект JavaScript - это встроенный тип для коллекции из нуля или более свойств. Свойства - это контейнеры, которые содержат другие объекты, примитивные значения или функции.

Конструкторы в JavaScript

Функции - это обычные объекты (реализующие [[Call]]в терминах ECMA-262) с дополнительной возможностью вызова, но играют другую роль в JavaScript: они становятся конструкторами (фабриками для объектов), если вызываются черезnewоператор. Таким образом, конструкторы являются грубым аналогом классов на других языках.

Каждая функция JavaScript на самом деле является экземпляром Function встроенный функциональный объект со специальным свойством с именем prototypeиспользуется для реализации наследования на основе прототипов и общих свойств. Каждый объект, созданный функцией конструктора, имеет неявную ссылку (называемую прототипом или__proto__) к значению его конструктора prototype.

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

Цепочка прототипов

Объект указывает свой прототип через внутреннее свойство [[Prototype]] или __proto__. Отношения прототипа между двумя объектами связаны с наследованием: каждый объект может иметь другой объект в качестве своего прототипа. Прототипом может бытьnull значение.

Цепочка объектов, соединенных __proto__свойство называется цепочкой прототипов. Когда делается ссылка на свойство в объекте, это ссылка на свойство, обнаруженное в первом объекте в цепочке прототипов, который содержит свойство с этим именем. Цепочка прототипов ведет себя так, как будто это один объект.

См. Это изображение (извлечено из этого блога):

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

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

Почти все объекты являются экземплярами Object, так как Object.prototypeявляется последним в их цепочке прототипов. НоObject.prototype не является примером Object так как Object.prototype.__proto__ имеет ценность null.

Вы также можете создать объект с null прототип вроде этого:

var dict = Object.create(null);

Такой объект является лучше картой (словарь), чем буквальный объект, поэтому этот образец иногда называют ДИКТ паттерном (ДИКТ для словаря).

Примечание: буквальные объекты, созданные с использованием {} являются экземплярами Object поскольку ({}).__proto__ это ссылка на Object.prototype.

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

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

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.__proto__

В то время как 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

Прототипы в JavaScript сбивают с толку всех

Конструктор любого типа (Object, String, Array и т. д.) изначально связан с создавшим их. После создания значений/объектов типов объектов им назначаются собственные прототипы, которые являются уникальным свойством и объектом, который конструктор функций создает при создании каждого значения. Но прототипы всех объектов/типов (Object, String, Array и т. д.) в JavaScript — это все . Все они происходят от функций и их конструкторов, необходимых для создания экземпляров объектов и примитивных значений в памяти! Только после того, как их значения будут созданы их конструкторами функций, им будут назначены их собственные уникальные прототипы , как свойство «prototyoe», так и прототип объекта, от которого они наследуются.

Это то, о чем вам не говорят 99% онлайн-страниц в Интернете!

Например, тип (или String Array, Boolean и т. д.) всегда имеет конструктор или, который вытекает изприсвоен тип "Число". Вот почему «Число» называется «Конструктор». Итак, его прототип — это когда вы проверяете. Как только его функция или конструктор построит истинныйпримитив или тип, ему присваивается собственный уникальный прототип. Давайте докажем это ниже!

Вот более простое объяснение. Ниже показано, как большинство объектов в JavaScript наследуют, начиная с нуля, и заканчивая типом объекта:

      String   < Function < Object < null
Array    < Function < Object < null
Object   < Function < Object < null
Function < Function < Object < null

Вот доказательство! Ниже я просто прошу прототип, найденный для каждого объекта. Примечание:просто сообщает нам строковое имя прототипа:

      Object.prototype.toString.call(String);// [object Function]
Object.prototype.toString.call(Array);// [object Function]
Object.prototype.toString.call(Object);// [object Function]
Object.prototype.toString.call(Function);// [object Function]

Object.prototype.toString.call(String.__proto__);// [object Function]
Object.prototype.toString.call(Array.__proto__);// [object Function]
Object.prototype.toString.call(Object.__proto__);// [object Function]
Object.prototype.toString.call(Function.__proto__);// [object Function]

Object.prototype.toString.call(String.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Array.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Object.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Function.__proto__.__proto__);// [object Object]

Object.prototype.toString.call(String.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Array.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Object.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Function.__proto__.__proto__.__proto__);// [object Null]

Обратите внимание, что строка «[object Function]» говорит о том, что «прототип» или родительский объект для типа был «Function.prototype». Таким образом, это представление базовых родительских объектов прототипа, назначенных на каждом уровне. Теперь давайте объясним это более подробно...

Прототип в JavaScript — это слово , означающее следующее:

  • Все объекты в JavaScript в конечном счете наследуются от серии прототипов или «базовых классов», которые присваивают свои различные свойства и функции посредством наследования. Это спускается каскадом вниз по дереву к дочернему элементу внизу. В JavaScript ВСЕ ОБЪЕКТЫ в конечном итоге наследуются от Object.prototype , который находится близко к вершине этого дерева наследования.
  • Термин «прототип» означает специальный объект со свойствами и методами, унаследованными дочерними объектами.
  • «Прототип» также является специальным свойством, данным всем объектам в JavaScript, которое назначает данный объект в качестве родительского прототипа дочернему, но также предоставляет доступ к изменению прототипа. Он управляет фактическим прототипом, назначенным дочернему объекту, но также действует как истинное свойство класса, поскольку вы можете использовать его для управления прототипом дочернего объекта. Я не рекомендую вам делать это, но вы можете изменить исходный Object.prototype, унаследованный всеми объектами, добавив новые свойства, используя простое добавление свойств, или добавив свойства через литерал объекта, содержащий свойства :
          Object.prototype.myproperty = "Hello World";
    Object.prototype.myobjectproperties = {text1: "Hello", text2: "World"};
  • "prototype" свойство выражается в сочетании с именем дочернего объекта как "MyObjectType.prototype". Это новое имя теперь является одновременно идентификатором родительского прототипа и инструментом для его изменения. Но это НЕ ссылка на фактический объект-прототип! (Это делается ниже с использованием __proto__). Он присваивается всем новым объектам при создании этого типа. Сначала он присваивается конструктору функции, создавшему объект, а затем передается объекту, который создает конструктор функции.

  • «__proto__» — это ссылка на фактический объект-прототип, назначенный дочернему элементу. Это также свойство, но это ссылка. Таким образом, он используется для перехода вверх по дереву объектов-прототипов, унаследованных дочерним объектом, и доступа к ним и их свойствам. Этот пример ниже идет вверх по дереву от созданного литерала объекта и заканчивается наверху «нулевым»:

          alert({}.__proto__.__proto__);// null

Странности в прототипе

Итак, в наследовании JavaScript все начинается с типа Function! Почему это? Это потому, что вы не можете создать ни один из «типов» объектов (объект, массив, функция, строка и т. д.) без функции. И когда вы это делаете, они все равно создаются из «конструктора», вызываемого где-то в функции. Функция и ее конструктор — это то, что не только создает новые объекты из типов, но также присваивает свойство «прототип», свойство «__прото__» и фактическое дерево унаследованных прототипов или объектов, которые будет использовать дочерний объект.

В JavaScript есть два состояния объектов: «типы» и фактически созданные объекты. Вот почему «Объект» — это не то же самое, что созданный объект, поскольку «const x = {}». И именно поэтому «тип» начинается с другого наследования или прототипов, отличного от его окончательного.

Проверь это!

      // The Array type has a prototype of "Function.prototype"
alert(Object.prototype.toString.call(Array));// [object Function]

// But an instance of an Array object has a NEW prototype of "Array.prototype" that the function prototype's constructor created for the object!
const myarray = [];
alert(Object.prototype.toString.call(myarray));// [object Array]

Итак, что случилось?

Оказывается, КОНСТРУКТОР ФУНКЦИИ создает и присваивает окончательныйпри создании объекта. Но этот пользовательский прототип может быть изменен как до, так и после создания объекта массива со многими другими свойствами, объектами и т. д. Таким образом, окончательный назначенный прототип устанавливается конструктором объекта Function, который, как показано выше, был исходным прототипом типов Array.

Итак, поймите, что это основной прототип всех типов объектов в JavaScript ! Он находится под всеми объектами, но является инструментом для создания окончательного экземпляра объекта, которому при создании назначается собственный прототип. Обратите внимание, что у «Array.prototype» есть родительский прототип, у которого есть родитель «null». Таким образом, остается верхний родитель, унаследованный всеми этими объектами. Но при их создании конструктор изменяет непосредственного родителя всех дочерних объектов при создании новых объектов.

Обратите внимание, чтополучает многие из своих функций от своего собственного Object.prototype, который он также наследует. Прототип, который он создает для ваших созданных объектов, также сделан из этого родительского прототипа. Итак, в конце концов. предоставляет полезные свойства, необходимые для типов функций и всех типов для создания и управления назначенным им прототипом. Просто помните, что функция, такая как объект, — это специальный предварительно созданный тип со специальными инструментами и функциями, необходимыми для создания всех типов объектов!

Последний тест... давайте посмотрим, как работает прототип для ПОЛЬЗОВАТЕЛЬСКИХ ОБЪЕКТОВ, которые мы создаем. В приведенном ниже примере показано, что конструктор функции (часть Function.prototype ) присваивает свойство «прототип» созданным объектам, НО может быть настроен с помощью различных свойств и методов до или после назначения прототипу объектов объекта.. Это показывает, что окончательный прототип вашего объекта не обязательно должен быть статической копией объекта.унаследованные свойства, но вы можете создать что-то совершенно новое!

      let newPet;
function Pet() {
  this.fourlegs = true;
}

var Cat = {
  type : "cat"
}

var Dog = {
  type : "dog"
}

// We can see the prototype our constructor created for us
// and modify it as we like! Here we assigned it to an object
// which only means the prototype will merge "Cat" object's
// properties into the Pet.prototype.
Pet.prototype = Cat;

newPet = new Pet();
alert(newPet.type);// cat - inherited the Cat Object's properties in the prototype

Pet.prototype = Dog;

newPet = new Pet();
alert(newPet.type);// dog - inherited the Dog Object's properties in the prototype

alert(newPet.fourlegs);// true - this shows, even though you replace prototype, it ADDs the new types but does NOT erase the existing object properties! This must mean "prototype" is dynamically additive and rebuilt until the final "Pet" prototype is complete.

// Now change the "Pet.prototype" so all new objects have a new property.
Pet.prototype.furcolor = "white";
newPet = new Pet();
alert(newPet.furcolor);// "white"

// So you can see the "Pet.prototype" is dynamic, something you can tell the function constructor to modify!
Другие вопросы по тегам