Наследование прототипов в JavaScript работает следующим образом.
Каждый объект Function имеет свойство с именем «prototype». Когда объект создается с использованием «new», среда выполнения выделяет пустой объект и устанавливает для его свойства «prototype» то же значение, что и для свойства «prototype» функции конструктора. Стандартный JS не имеет возможности обновить прототип этого пустого объекта впоследствии. Свойства могут быть добавлены или удалены из этого объекта, либо в функции конструктора, либо позже. Значение по умолчанию:
MyFunction.prototype = Object.prototype
Всякий раз, когда к свойству обращаются с помощью «this. [Property]», среда выполнения сначала проверяет, есть ли у свойства «this», созданного выше, свойство. Если не найдено, то среда выполнения просматривает «this.prototype», затем «this.prototype.prototype» и т. Д. До тех пор, пока не будет проверен Object.prototype. Если его не найти, в качестве значения свойства будет возвращено «неопределенное».
obj -> obj.prototype -> obj.prototype.prototype -> Object.prototype
Например,
var myPrototype = { prop : "ABC" }
function MyConstructor()
{
}
MyConstructor.prototype = myPrototype
var o = new MyConstructor()
alert( o.prop )
В приведенном выше описании при разрешении «o.prop» среда выполнения сначала ищет в «o» свойство «prop». Не найдя его на «o», среда выполнения смотрит на «myPrototype». Найдя его там, возвращается значение «ABC».
Обратите внимание, что ссылка "this" всегда относится к объекту, созданному выше (например, "o"). Таким образом, если бы вы присвоили значение свойству прототипа, используя «this», среда выполнения фактически создаст новое свойство с таким именем и поместит его в объект, на который ссылается «this», а не обновление значения в прототипе, таким образом, «затеняя» исходное значение. Чтобы изменить значение прототипа, необходимо напрямую ссылаться на объект прототипа либо через «this.prototype». или с помощью другой ссылки на этот объект, скажем «thePrototypeObject. [property]», при условии, что для объекта-прототипа назначена переменная.
o.prop = "DEF"
alert( o.prop )
alert( myPrototype.prop )
В этом случае оператор присваивания создает новое свойство с именем «prop» для «o» . Итак, первое предупреждение печатает «DEF», тогда как второе печатает «ABC».
var o = new MyConstructor()
myPrototype.prop = "DEF"
alert( o.prop )
alert( myPrototype.prop )
В в этом случае свойство «prop» исходного прототипа обновляется, поэтому оба они выводят одно и то же значение («ABC»).
В вашем примере выше,
var Shape = function()
{
this.toString_ = function() { alert(this.UL)}
}
Shape.prototype.UL = "<UL></UL>"
var _2D = function() { this.name = "_2D"}
_2D.prototype = new Shape()
var i = new _2D()
i.toString_()
Цепочка прототипов выглядит следующим образом:
Shape.prototype -> Object.prototype
Object.prototype.UL = "<UL></UL>"
_2D.prototype -> (new Shape) -> Object.prototype
i.prototype -> (new Shape) -> Object.prototype
Итак, при разрешении "toString_ ()" среда выполнения проверяет сначала "i" и, не найдя его там, ищет объект (новый Shape). Находя его там, он вызывает «toString_ ()», передавая «i» как «this». При разрешении "this.UL" среда выполнения сначала смотрит на "i", затем (новая форма), затем на "Object.prototype", наконец, возвращая найденное там значение.