Связь между [[Prototype]] и прототипом в JavaScript
С http://www.jibbering.com/faq/faq_notes/closures.html:
Примечание: ECMAScript определяет внутреннее свойство [[prototype]] внутреннего типа объекта. Это свойство не доступно напрямую в скриптах, но это цепочка объектов, на которые ссылается внутреннее свойство [[prototype]], которое используется в разрешении средства доступа к свойству; цепочка прототипов объекта. Существует открытое свойство prototype, позволяющее присваивать, определять и манипулировать прототипами в сочетании с внутренним свойством [[prototype]]. Детали взаимосвязи между ними описаны в ECMA 262 (3-е издание) и выходят за рамки этого обсуждения.
Каковы детали отношений между ними? Я просмотрел ECMA 262 и все, что я прочитал, это что-то вроде:
На соответствующий прототип конструктора может ссылаться выражение программы constructor.prototype,
Нативные объекты ECMAScript имеют внутреннее свойство, называемое [[Prototype]]. Значение этого свойства равно нулю или объекту и используется для реализации наследования.
Каждая встроенная функция и каждый встроенный конструктор имеет объект-прототип Function, который является начальным значением выражения Function.prototype
Каждый встроенный объект-прототип имеет объект-прототип Object, который является начальным значением выражения Object.prototype (15.3.2.1), в качестве значения его внутреннего свойства [[Prototype]], кроме самого объекта-прототипа Object.
Из всего этого я понимаю, что свойство [[Prototype]] эквивалентно prototype
свойство практически для любого объекта. Я ошибаюсь?
3 ответа
Я считаю, что вы правы в большинстве случаев.
У каждого объекта есть скрытый [[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 функции конструктора может быть переназначено, но [[Prototype]]
объекта не может быть переназначен после того, как объект создан. Так что если вы делаете:
C.prototype = P2;
затем
obj.constructor.prototype != Object.getPrototypeOf(obj)
Потому что прототип C
сейчас P2
, но [[Prototype]]
из obj
все еще P1
,
Обратите внимание, что только функции имеют prototype
имущество. Обратите внимание также, что prototype
свойство функции не совпадает с [[Prototype]]
свойство функции!
Чтобы ответить на ваш вопрос напрямую: логически это личная копия объекта 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's assume that the old prototype didn't define "life"
console.log(x.life); // undefined
x.log(); // ...logging...
В полном соответствии со стандартом [[prototype]]
недоступно, но Mozilla расширяет стандарт __proto__
свойство (только для чтения), отображающее обычно скрытое [[prototype]]
:
Снова, __proto__
может быть легализован в следующем стандарте ES3.1.
В дополнение к ответу olavk: Некоторые реализации JavaScript (например, mozilla) позволяют напрямую обращаться к свойству [[Prototype]]...