Связь между [[Prototype]] и прототипом в JavaScript - PullRequest
19 голосов
/ 20 декабря 2008

С http://www.jibbering.com/faq/faq_notes/closures.html:

Примечание: ECMAScript определяет внутреннее свойство [[prototype]] внутреннего типа объекта. Это свойство напрямую недоступно для скриптов, но это цепочка объектов, на которые ссылается внутреннее свойство [[prototype]], которое используется в разрешении средства доступа к свойству; цепь прототипа объекта. Существует открытое свойство prototype, позволяющее присваивать, определять и манипулировать прототипами в сочетании с внутренним свойством [[prototype]]. Подробности взаимосвязи между двумя описаны в ECMA 262 (3-е издание) и выходят за рамки этого обсуждения.

Каковы подробности отношений между ними? Я просмотрел ECMA 262, и все, что я прочитал, это что-то вроде:

На соответствующий прототип конструктора может ссылаться выражение программы constructor.prototype,

Нативные объекты ECMAScript имеют внутреннее свойство, называемое [[Prototype]]. Значение этого свойства равно null или объекту и используется для реализации наследования.

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

Каждый встроенный объект-прототип имеет объект-прототип Object, который является начальным значением выражения Object.prototype (15.3.2.1), как значение его внутреннего свойства [[Prototype]], за исключением Object Сам объект-прототип.

Из всего этого я понял, что свойство [[Prototype]] эквивалентно свойству prototype практически для любого объекта. Я ошибаюсь?

Ответы [ 3 ]

46 голосов
/ 20 декабря 2008

Я считаю, что вы правы в большинстве случаев.

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

1010 * Е.Г. *

function C() {}
C.prototype = P1;  
var obj = new C();  // obj.[[Prototype]] is now P1.

Вы можете получить свойство [[Prototype]], используя Object.getPrototypeOf(<obj>). (Этот метод указан в ECMAScript 5. В старых версиях JavaScript нет стандартного способа чтения [[Prototype]]).

Вы можете обычно добраться до прототипа через конструктор, например ::1010 *

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]] функции!

12 голосов
/ 20 декабря 2008

Чтобы ответить на ваш вопрос напрямую: логически это личная копия объекта 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 .

4 голосов
/ 20 декабря 2008

В дополнение к ответу olavk: Некоторые реализации JavaScript (например, mozilla ) позволяют напрямую обращаться к свойству [[Prototype]] ...

...