Чим __proto__ відрізняється від constructor.prototype?


163
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__властивості?


30
Ця графічна діаграма допоможе вам зрозуміти різницю між прототипом та прототипом . Ви можете слідкувати за прото ланцюжок від newtoy об'єкта, а потім ви зрозумієте , чому третій Прото з newtoy є недійсним.
біт

Також зрозуміло з діаграми, що newtoy.prototypeне дорівнює newtoy.constructor.prototypeі тому newtoy.constructor.prototypeне буде мати властивості викликати rating. Так newtoy.constructor.prototype.constructor.propertyсамо не буде вказано властивість rating.
біт

Опублікувати в останньому коментарі: тому newtoy.constructor.prototypeбуде вказано властивість, яку називають рейтингом. Аналогічно newtoy.constructor.prototype.constructor.propertyматиметься також майно, яке називається рейтингом.
біт


1
@Royi Namir Я завантажив jsViz на github. Ось демонстраційний сайт . Будь ласка, не забувайте, наскільки непорушним (і брудним) є фактичний код. Його супер старий проект, якого я не торкався назавжди.
біт

Відповіді:


210

Я нещодавно намагався обернутись головою і, нарешті, придумав цю "карту", яку, на мою думку, проливає повне світло на цю справу

http://i.stack.imgur.com/KFzI3.png введіть тут опис зображення

Я знаю, що я не перший, хто це робив, але було цікавіше з'ясувати, що знайти :-). У будь-якому разі, після цього я знайшов, наприклад, цю ще одну діаграму, яку, на мою думку, говорить про те саме:

Макет об’єкта Javascript

Найдивніше для мене було виявлення, що замість цього Object.__proto__вказує , але я впевнений, що для цього є вагома причина :-)Function.prototypeObject.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);

2
@utsaina Дуже круто. Оформити ще одне графічне зображення коду, який розмістив ОП. І я думаю, наші діаграми узгоджуються з точки зору технічних деталей.
біт

43
Причина, на яку Object.__proto__вказує, Function.prototypeполягає в тому Object(), що сама по собі є нативною функцією, яка створює порожній об'єкт. Тому Object()є функцією. Ви побачите, що всі інші основні __proto__властивості типів вказують на Function.prototype. Object, Function, String, Number, І Arrayвсе успадкують функціональний прототип.
Поворот

@drodsou ваше 2-е посилання є приголомшливим. Перевірте це, будь ласка;) mollypages.org/misc/js.mp Приємне пояснення: D
abhisekp

@Swivel "Отже, Object () - це функція" - ви мали на увазі сказати, що "Object" є функцією? без ()
giorgim

2
@GiorgiMoniava Правильно. Objectсама по собі функція; результат виконання виклику Object(тобто повернене значення запущеного Object()) не є функцією.
Поворот

67

constructorє заздалегідь визначеним [[DontEnum]] властивістю об'єкта, на який вказує prototypeвластивість об’єкта функції, і спочатку вказуватиме на сам об'єкт функції.

__proto__ еквівалентна внутрішній [[прототип]] властивості об'єкта, тобто його фактичному прототипу.

Коли ви створюєте об'єкт з newоператором, його внутрішнє [[прототип]] властивість буде встановлено на об'єкт, на який вказує prototypeвластивість функції конструктора .

Це означає, що .constructorбуде оцінюватися .__proto__.constructor, тобто функція конструктора, що використовується для створення об'єкта, і, як ми дізналися, protoypeвластивість цієї функції використовувалося для встановлення [[прототипу]] об'єкта.

Звідси випливає, що .constructor.prototype.constructorє ідентичним .constructor(доки ці властивості не були перезаписані); дивіться тут для більш детального пояснення.

Якщо __proto__це можливо, ви можете пройти фактичний прототип ланцюга об'єкта. Неможливо зробити це в звичайному ECMAScript3, оскільки JavaScript не був розроблений для ієрархій глибокого успадкування.


3
Це посилання "тут" - це золотий стандарт. Зайдіть туди, якщо хочете повного опису.
Ricalsin

Гарний улов з .constructor.prototypeприкуванням. Мені також було незрозуміло для мене, поки я не бачив, що .constructorце рівне .__proto__.constructor. Що просто означає рух між функцією конструктора та його прототипом.
Johnny_D

30

Прототипне успадкування 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властивість не існує у створених об'єктах, але успадковується від прототипу.

введіть тут опис зображення


@xorcus Чи можете ви пояснити це: new MyFunction()створює екземпляр об'єкта , який його __proto__слід послатися на його CTOR прототип , який MyFunction.prototype.Так чому ж MyFunction.prototype.__proto__referes до Object.prototype? він повинен віднестись (як і мій перший зразок) до прототипу свого ctor, який є MyFunction.prototype(зауважте, що MyFunction.prototypeце інсталля Myfunction)
Royi Namir

@ Рой Намір: MyFunction.prototype .__ proto__ відноситься до Object.prototype, оскільки MyFunction.prototype є об'єктом. Object.prototype успадковується всіма об'єктами (зазвичай на цьому закінчується ланцюг успадкування прототипу). Я не згоден, що MyFunction.prototype є екземпляром MyFunction. obj instanceof MyFunction <=> MyFunction.prototype.isPrototypeOf (obj) <=> MyFunction.prototype існує у ланцюзі прототипів obj. Це не так для об’єкта MyFunction.prototype
xorcus

14

Objectє Єва, і FunctionАдам, Адам ( Function) використовує свою кістку ( Function.prototype) для створення Єви ( Object). Тоді хто створив Адама (Function )? - Винахідник мови JavaScript :-).

Відповідно до відповіді utsaina, я хочу додати більше корисної інформації.

Найдивніше для мене було виявлення, що замість цього Object.__proto__ вказує , але я впевнений, що для цього є вагома причина :-)Function.prototypeObject.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як це звичайний клас.

Власне кажучи, у механізмі JavaScript Google Chrome наступні 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)? Подумай над цим :-)


Погодьтеся з цим, за винятком останнього: що function Empty() {}ви називаєте рівним Function.prototype тощо? Який код ви використовували в хромованій консолі?
drodsou

2
Я виправив останнє, на що ти вказав. Їх цінність - function Empty() {}у Google Chrome. Я також додав консольний вихід.
Пітер Лі

всі функції є instanceof Function, отже, всі функції успадковують ( _ _proto_ _) від Function.prototype. Це так просто, як це :)
xorcus

Вибачте за коментар до старої теми. Але чи створені вони винахідником мови?
Patel Parth

6

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

Це полегшило б вам проблему

Тож давайте подивимося, що відбувається:

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__

Перед цим запам’ятайте дві речі щодо __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

Кожна функція створює прототип. І коли ми створимо об'єкт за допомогою цього конструктора функцій, то властивість __proto__ мого об'єкта почне вказувати на прототип цієї функції.


1
Я думаю, ти мав намір сказати __proto__власність.
демікс

Так. Я мав на увазі прото- властивість об'єкта. Сподіваюся, інформація була корисною.
Апоорв Наг

2

Якщо всі ці цифри були непосильними, давайте подивимося, що означають властивості.

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. Це властивість являє собою функцію, яка створила об'єкт-прототип.

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

0

Коротка відповідь: __proto__це посилання на prototypeвластивість конструктора, який створив об'єкт.

Об'єкти в JavaScript

Об'єкт JavaScript - це вбудований тип для колекції нульових або більше властивостей. Властивості - це контейнери, що містять інші об'єкти, примітивні значення або функції.

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

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

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

Конструктор prototype- це свого роду план будівельних об'єктів, оскільки кожен об'єкт, створений конструктором, успадковує посилання на нього prototype.

Прототип ланцюга

Об'єкт вказує свій прототип через внутрішню властивість [[Prototype]]або __proto__. Зв'язок прототипу між двома об'єктами стосується спадкування: кожен об'єкт може мати ще один об'єкт як свій прототип. Прототипом може бути nullзначення.

Ланцюжок об'єктів, з'єднаних __proto__властивістю, називається ланцюгом прототипу . Коли посилання робиться на властивість об’єкта, це посилання є на властивість, що зустрічається в першому об'єкті ланцюга прототипу, що містить властивість цього імені. Ланцюг прототипу поводиться так, ніби це єдиний об'єкт.

Дивіться це зображення (витягнуте з цього блогу ):

proto.jpg

Щоразу, коли ви намагаєтеся отримати доступ до властивості в об'єкті, JavaScript починає пошук його в цьому об’єкті і продовжує його прототип, прототип прототипу тощо, поки не з'явиться властивість або якщо воно не __proto__містить значення null.

Цей тип успадкування за допомогою ланцюга прототипу часто називають делегуванням, щоб уникнути плутанини з іншими мовами за допомогою ланцюга класів.

Практично всі об'єкти є екземплярами Object, тому що Object.prototypeвін останній у ланцюзі прототипу. Але Object.prototypeце не екземпляр, Objectоскільки він Object.prototype.__proto__містить значення null.

Ви також можете створити об'єкт з таким nullпрототипом:

var dict = Object.create(null);

Такий об'єкт є краще картою (словник) , ніж буквальний об'єкт, тому цей зразок іноді називають диктує патерном ( диктує для словника).

Примітка: буквальні об'єкти, створені за допомогою, {}є екземплярами, Objectоскільки ({}).__proto__є посиланням на Object.prototype.


Будь ласка, вкажіть джерело цитат та артефактів, які ви використовуєте. Здається, картина походить від giamir.com/pseudoclasses-and-prototypal-inheritance-in-JS , чи є у вас авторські права на це?
Бергі

@Bergi Я цитував джерело зображення. Більшість цитат, які я використав, або витягнуті зі стандарту JS, або MDN
eigenslacker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.