Связь между [[Prototype]] и прототипом в JavaScript
Из http://www.jibbering.com/faq/faq_notes/closures.html:
Примечание. ECMAScript определяет внутреннее свойство [[prototype]] для внутреннего типа объекта. Это свойство напрямую не доступно с помощью скриптов, но это цепочка объектов, на которые ссылается внутреннее свойство [[prototype]], которое используется при разрешении доступа к свойствам; цепь прототипа объекта. Существует общедоступное свойство прототипа, позволяющее назначать, определять и манипулировать прототипами в сочетании с внутренним свойством [[prototype]]. Детали отношения между двумя описаны в ECMA 262 (3-е издание) и выходят за рамки этого обсуждения.
Каковы детали взаимоотношений между ними? Я просматривал ECMA 262, и все, что я читал, есть такие вещи, как:
К конструкторам, связанным с прототипом, может ссылаться конструктор выражения программы .prototype,
Собственные объекты ECMAScript имеют внутреннее свойство, называемое [[Prototype]]. Значение этого свойства равно либо null, либо объекту и используется для реализации наследования.
Каждая встроенная функция и каждый встроенный конструктор имеют объект-прототип функции, который является начальным значением выражения Function.prototype
Каждый встроенный объект-прототип имеет объект-прототип объекта, который является начальным значением выражения Object.prototype(15.3.2.1), как значение его внутреннего свойства [[Prototype]], за исключением объекта Object самого прототипа.
Из этого все, что я собираю, является то, что свойство [[Prototype]] эквивалентно свойству prototype
для почти любого объекта. Я ошибаюсь?
Ответы
Ответ 1
Я считаю, что вы правы в большинстве случаев.
Каждый объект имеет скрытое свойство [[Prototype]]
, которое используется для наследования. Кроме того, функции имеют общедоступное свойство prototype
, которое используется только тогда, когда функция используется как конструктор. Когда объект создается с использованием new
, свойство [[Prototype]]
нового объекта устанавливается в свойство prototype
функция, которая использовалась в качестве конструктора.
например.
function C() {}
C.prototype = P1;
var obj = new C(); // obj.[[Prototype]] is now P1.
Вы можете получить свойство [[Prototype]]
, используя Object.getPrototypeOf(<obj>)
. (Этот метод указан в ECMAScript 5. В старых версиях JavaScript нет стандартного способа чтения [[Prototype]]
).
Обычно вы можете перейти к прототипу через конструктор, например:
obj.constructor.prototype == Object.getPrototypeOf(obj)
Но это не всегда так, поскольку свойство прототипа функции конструктора можно переназначить, но объект [[Prototype]]
объекта не может быть переназначен после создания объекта. Итак, если вы это сделаете:
C.prototype = P2;
затем
obj.constructor.prototype != Object.getPrototypeOf(obj)
Поскольку прототип C
теперь P2
, но [[Prototype]]
of obj
все еще P1
.
Обратите внимание, что это только функции, обладающие свойством prototype
. Заметим также, что свойство prototype
функции не совпадает с свойством [[Prototype]]
функции!
Ответ 2
Чтобы ответить на ваш вопрос напрямую: логически это частная копия объекта свойства prototype
его конструктора. Используя метаязык, создаются объекты:
// not real JS
var Ctr = function(...){...};
Ctr.prototype = {...}; // some object with methods and properties
// the object creation sequence: var x = new Ctr(a, b, c);
var x = {};
x["[[prototype]]"] = Ctr.prototype;
var result = Ctr.call(x, a, b, c);
if(typeof result == "object"){ x = result; }
// our x is fully constructed and initialized at this point
В этот момент мы можем изменить прототип, и это изменение будет отражено всеми объектами класса, потому что они ссылаются на прототип по ссылке:
Ctr.prototype.log = function(){ console.log("...logging..."); };
x.log(); // ...logging..
Но если мы изменим прототип на конструкторе, уже созданные объекты будут продолжать ссылаться на старый объект:
Ctr.prototype = {life: 42};
// let assume that the old prototype didn't define "life"
console.log(x.life); // undefined
x.log(); // ...logging...
В полном соответствии со стандартом [[prototype]]
недоступно, но Mozilla расширяет стандарт с помощью свойства __proto__
(только для чтения), которое подвергает обычно скрытому [[prototype]]
:
Опять же, __proto__
может быть легализован в следующем стандарте ES3.1.
Ответ 3
В дополнение к ответу olavk: некоторые реализации JavaScript (например, mozilla) позволяют напрямую получить доступ к свойству [[Prototype]]...