Чем __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 ответов
Я пытался обернуть это вокруг недавно и наконец придумал эту "карту", которая, я думаю, проливает полный свет на этот вопрос
Я знаю, что я не первый, кто придумывает это, но было интереснее выяснить это, чем найти это:-). Во всяком случае, после этого я нашел, например, еще одну диаграмму, которая, по-моему, говорит в основном то же
Самым удивительным для меня было открытие, что 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
, Вместо этого экземпляр 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
ХОРОШО. Тогда кто создает специальные 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__
:
Когда вы создаете объект с
new
оператор, его внутренний[[Prototype]]
/proto__
свойство будет установлено наprototype
свойство (1) егоconstructor function
или "создатель", если хотите.Жестко закодировано в 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]
Итак, что случилось?
Оказывается, КОНСТРУКТОР ФУНКЦИИ создает и присваивает окончательный
Итак, поймите, что это основной прототип всех типов объектов в JavaScript ! Он находится под всеми объектами, но является инструментом для создания окончательного экземпляра объекта, которому при создании назначается собственный прототип. Обратите внимание, что у «Array.prototype» есть родительский прототип, у которого есть родитель «null». Таким образом, остается верхний родитель, унаследованный всеми этими объектами. Но при их создании конструктор изменяет непосредственного родителя всех дочерних объектов при создании новых объектов.
Обратите внимание, что
Последний тест... давайте посмотрим, как работает прототип для ПОЛЬЗОВАТЕЛЬСКИХ ОБЪЕКТОВ, которые мы создаем. В приведенном ниже примере показано, что конструктор функции (часть 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!