Prototype inheritance in JavaScript works like this.
Every Function object has a property called "prototype". When an object is created using "new", the runtime allocates an empty object and sets its "prototype" property to the same value as the constructor function's "prototype" property. Standard JS has no way to update this blank object's prototype afterwards. Properties can then be added or removed from this object, either in the constructor function or later. The default value is:
MyFunction.prototype = Object.prototype
Whenever a property is accessed with "this.[property]", the runtime first looks to see if the "this" object created above has the property. If not found, then the runtime looks on "this.prototype", then "this.prototype.prototype", etc. until Object.prototype is checked. Failing to find it there will return "undefined" as the property value.
obj -> obj.prototype -> obj.prototype.prototype -> Object.prototype
For example,
var myPrototype = { prop : "ABC" }
function MyConstructor()
{
}
MyConstructor.prototype = myPrototype
var o = new MyConstructor()
alert( o.prop )
In the above, when resolving "o.prop", the runtime first looks on "o" for a property called "prop". Failing to find it on "o", the runtime looks on "myPrototype". Finding it there, the value "ABC" is returned.
Note that the "this" reference always refers to the object created above (e.g., "o"). So, if you were to assign a value to a property on the prototype using "this", the runtime will actually create a new property of that name and put it on the object referenced with "this" rather than updating the value in the prototype, thus "shadowing" the original value. In order to modify the prototype's value, one would need to directly reference the prototype object, either via "this.prototype." or via a different reference to that object, say "thePrototypeObject.[property]", assuming you had a variable assigned to the prototype object.
o.prop = "DEF"
alert( o.prop )
alert( myPrototype.prop )
In this case, the assignment statement creates a new property called "prop" on "o". So, the first alert prints "DEF", whereas the second prints "ABC".
var o = new MyConstructor()
myPrototype.prop = "DEF"
alert( o.prop )
alert( myPrototype.prop )
In this case, the original prototype's "prop" property is updated, so both will print the same value ("ABC").
In your example above,
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_()
The prototype chain looks like the following:
Shape.prototype -> Object.prototype
Object.prototype.UL = "<UL></UL>"
_2D.prototype -> (new Shape) -> Object.prototype
i.prototype -> (new Shape) -> Object.prototype
So, when resolving "toString_()", the runtime examines first "i" and, failing to find it there, looks on the (new Shape) object. Finding it there, it calls "toString_()" passing "i" as "this". When resolving "this.UL", the runtime first looks on "i", then (new Shape), then on "Object.prototype", finally returning the value it finds there.