JavaScript inheritance and the constructor property - javascript

Consider the following code.
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
Why isn't the constructor updated for b and c?
Am I doing inheritance wrong?
What is the best way to update the constructor?
Further, please consider the following.
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
Given that (new c()).constructor is equal to a() and Object.getPrototypeOf(new c()) is a{ }, how is it possible for instanceof to know that new c() is an instance of c?
http://jsfiddle.net/ezZr5/

Okay, let's play a little mind game:
From the above image we can see:
When we create a function like function Foo() {}, JavaScript creates a Function instance.
Every Function instance (the constructor function) has a property prototype which is a pointer.
The prototype property of the constructor function points to its prototype object.
The prototype object has a property constructor which is also a pointer.
The constructor property of the prototype object points back to its constructor function.
When we create a new instance of Foo like new Foo(), JavaScript creates a new object.
The internal [[proto]] property of the instance points to the prototype of the constructor.
Now, the question arises that why doesn't JavaScript attach the constructor property to the instance object instead of the prototype. Consider:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
As you can see the constructor property is just another method of the prototype, like area in the example above. What makes the constructor property special is that it's used to initialize an instance of the prototype. Otherwise it's exactly the same as any other method of the prototype.
Defining the constructor property on the prototype is advantageous for the following reasons:
It's logically correct. For example consider Object.prototype. The constructor property of Object.prototype points to Object. If the constructor property was defined on the instance then Object.prototype.constructor would be undefined because Object.prototype is an instance of null.
It's treated no differently from other prototype methods. This makes the job of new easier since it doesn't need to define the constructor property on every instance.
Every instance shares the same constructor property. Hence it's efficient.
Now when we talk about inheritance, we have the following scenario:
From the above image we can see:
The derived constructor's prototype property is set to the instance of the base constructor.
Hence the internal [[proto]] property of the instance of the derived constructor points to it too.
Thus the constructor property of the derived constructor instance now points to the base constructor.
As for the instanceof operator, contrary to popular belief it doesn't depend on the constructor property of the instance. As we can see from above, that would lead to erroneous results.
The instanceof operator is a binary operator (it has two operands). It operates on an instance object and a constructor function. As explain on Mozilla Developer Network, it simply does the following:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
To put it simply if Foo inherits from Bar, then the prototype chain for the instance of Foo would be:
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
As you can see, every object inherits from the Object constructor. The prototype chain ends when an internal [[proto]] property points to null.
The instanceof function simply traverses the prototype chain of the instance object (the first operand) and compares the internal [[proto]] property of each object to the prototype property of the constructor function (the second operand). If they match, it returns true; and else if the prototype chain ends, it returns false.

By default,
function b() {}
then b.prototype has a .constructor property which is set to b automatically. However, you're currently overwriting the prototype and thus discarding that variable:
b.prototype = new a;
Then b.prototype does not have a .constructor property anymore; it was erased with the overwrite. It does inherit from a though, and (new a).constructor === a, and hence (new b).constructor === a (it is referring to the same property in the prototype chain).
Best to do is to simply setting it manually afterwards:
b.prototype.constructor = b;
You could also make a little function for this:
function inherit(what, from) {
what.prototype = new from;
what.prototype.constructor = what;
}
http://jsfiddle.net/79xTg/5/

constructor is a regular, non-enumerable property of the default value of the prototype property of function objects. Thus, assigning to prototype will lose the property.
instanceof will still work as it does not use constructor, but rather scans the prototype chain of the object for the (current) value of the function's prototype property, ie foo instanceof Foo is equivalent to
var proto = Object.getPrototypeOf(foo);
for(; proto !== null; proto = Object.getPrototypeOf(proto)) {
if(proto === Foo.prototype)
return true;
}
return false;
In ECMAScript3, there's no way to set a constructor property which behaves identically to the built-in one as user-defined properties are always enumerable (ie visible to for..in).
This changed with ECMAScript5. However, even if you set constructor manually, your code still has issues: In particular, it is a bad idea to set prototype to an instance of the parent-'class' - the parent constructor should not be called when the child-'class' is defined, but rather when child-instances are created.
Here's some ECMAScript5 example code for how it should be done:
function Pet(name) {
this.name = name;
}
Pet.prototype.feed = function(food) {
return this.name + ' ate ' + food + '.';
};
function Cat(name) {
Pet.call(this, name);
}
Cat.prototype = Object.create(Pet.prototype, {
constructor : {
value : Cat,
writable : true,
enumerable : false,
configurable : true
}
});
Cat.prototype.caress = function() {
return this.name + ' purrs.';
};
If you're stuck with ECMAScript3, you'll need to use a custom clone() function instead of Object.create() and won't be able to make constructor non-enumerable:
Cat.prototype = clone(Pet.prototype);
Cat.prototype.constructor = Cat;

Related

instanceof Operator doesn't classify instance as a type [duplicate]

Probably the least understood part of JavaScript, standing beside the prototype chain.
So the question is: how does...
new dataObj(args);
...actually create an object, and define its prototype chain/constructors/etc?
Best is to show an alternative, to fully understand this keyword.
The new operator uses the internal [[Construct]] method, and it basically does the following:
Initializes a new native object
Sets the internal [[Prototype]] of this object, pointing to the Function prototype property.
If the function's prototype property is not an object (a primitive values, such as a Number, String, Boolean, Undefined or Null), Object.prototype is used instead.
After creating the object, it calls the function, providing the object as its this value.
If the return value of the called function, is a primitive, the object created internally is returned.
Otherwise, if an object is returned, the object created internally is lost.
An equivalent implementation of what the new operator does, can be expressed like this (assuming that the ECMAScript 5 Object.create method is available):
function NEW(f) {
var obj, ret, proto;
// Check if `f.prototype` is an object, not a primitive
proto = Object(f.prototype) === f.prototype ? f.prototype : Object.prototype;
// Create an object that inherits from `proto`
obj = Object.create(proto);
// Apply the function setting `obj` as the `this` value
ret = f.apply(obj, Array.prototype.slice.call(arguments, 1));
if (Object(ret) === ret) { // the result is an object?
return ret;
}
return obj;
}
// Example usage:
function Foo (arg) {
this.prop = arg;
}
Foo.prototype.inherited = 'baz';
var obj = NEW(Foo, 'bar');
obj.prop; // 'bar'
obj.inherited; // 'baz'
obj instanceof Foo // true
The expression new C(arg1, arg2):
Assuming C is a JavaScript function (otherwise you get an error):
Creates a new empty object (no properties)
Sets the prototype of the new object to the value of the
"prototype" property of C.
Note: The default value of prototype for a function is an object (automatically created when the function is declared) with its prototype set to Object.prototype and a constructor property pointing back to the function C.
Note: The terminology can be confusing. The property named "prototype" is not the same as the prototype of the object. Only functions have the property named "prototype", but all objects have a prototype.
Calls the function C with 'this' set to the new object, and with the supplied arguments.
If calling the function C returns an object, this object is the result of the expression. Otherwise the newly created object is the result of the expression.
An alternative to new in ECMAScript 5 would be to use the builtin Object.createObject method.
new C(arg1, arg2) would be equivalent to:
var obj = Object.createObject(C.prototype);
C.apply(obj, [arg1, arg2]);
Standard JavaScript does not allow you to explicitly set the prototype of an object, so Object.createObject cannot be implemented in the language itself. Some implementations does allow it through the non-standard property __proto__. In that case, new C can be simulated like this:
var obj = {};
obj.__proto__ = C.prototype;
C.apply(obj, [arg1, arg2]);

javascript prototypical inheritance confused

given the standard way of achieving inheritance like this
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
why is necesary to do
SubClass.prototype = Object.create(BaseClass.prototype);
and end up with something like
function F(){}
F.prototype = BaseClass.prototype;
SubClass.prototype = new F();
instead of just doing
Subclass.prototype = BaseClass.prototype;
Assigning values to things in JavaScript really just copies a reference (unless working with primitive types). So when you do this:
Subclass.prototype = BaseClass.prototype;
What you're really doing is assigning the prototype of SubClass to the same location in memory as the prototype of BaseClass, therefore any prototype related changes you make to SubClass will also affect BaseClass. Here's a little example:
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = BaseClass.prototype;
SubClass.prototype.constructor = SubClass;
SubClass.prototype.subClassFunction = function(){
console.log("Added this to SubClass");
}
var baseObj = new BaseClass();
baseObj.subClassFunction(); // => "Added this to SubClass"
That's why you want to use
SubClass.prototype = Object.create(BaseClass.prototype);
because it will create a new and unique object with the specified prototype instead.
You can read more about how this function works here.
Object Reference!
Say BaseClass has a method toString:
BaseClass.prototype.toString = function() {
return 'foo'
}
But you redefine the toString method in SubClass:
SubClass.prototype.toString = function() {
return 'bar'
}
You'll expect:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'foo'
s.toString() //=> 'bar'
But if you use assignment to create inheritance what you will get is:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'bar'
s.toString() //=> 'bar'
Because BaseClass.prototype and SubClass.prototype now reference the same object
Inheritance, the __proto__ :
When an object SubClass inherits from another object BaseClass, in JavaScript that means that there is a special property SubClass.__proto__ = BaseClass.
Code :
function BaseClass() {
}
function SubClass() {
}
var BaseClass = new BaseClass();
var SubClass = new SubClass();
BaseClass.a = 5;
SubClass.b = 10;
SubClass.__proto__ = BaseClass;
console.log(SubClass);
Output :
Here, BaseClass is inherited by SubClass and BaseClass variable is accessable through the SubClass.
The syntax of JavaScript can be somewhat confusing. In JS, there isn't class inheritance but instance-based inheritance. An instance's parent is also called its prototype.
When you write instance.something or instance['something'], the JS engine looks at the instance to see if it has a member called something. If it doesn't, then it looks at the instance's prototype. If that object doesn't have the member something, it looks at the prototype's prototype, again and again until it finds the property or reaches an instance which inherits from null. In that case it will simply return undefined.
Functions have a special property called prototype which is something else. The function's .prototype is a simple object that has a constructor property which refers back to the function itself. When you create an object with the new keyword, that object's prototype will be set to the function's .prototype property. This is where the confusion comes from: the .prototype property of a constructor can be seen as the default prototype of all instances made with said constructor.
So when you add methods to a class by writing something like this:
MyClass.prototype.foo = function() {
alert('foo');
};
...you're actually storing the function in the prototype of all MyClass instances. When the JS engine looks at the instances of MyClass, it will look for the foo member which it won't find. Then it will look at the instance's prototype which happens to be set to MyClass.prototype and it will find the foo member and fetch it.
It's important to make the difference between an instance's prototype and a function's .prototype, but most people don't realize it. When they speak of a class's prototype, they're talking about MyClass.prototype. The instance prototype is accessible via __proto__ in many browsers, but that's not a standard feature of JavaScript and shouldn't be used in your code.
Now let's look at the code you're using to simulate class inheritance.
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
Object.create(parent) can be seen as a function that does this:
return {
__proto__ : parent
};
In other words, it creates a blank Object whose prototype is the passed object. Since all SubClass instances will inherit from Subclass.prototype, replacing SubClass.prototype with an object that inherits from BaseClass.prototype makes sure all SubClass instances also inherit from BaseClass.
However, as I said earlier, the default .prototype attribute of a function is an empty object whose .constructor is set to the function itself. So by manually setting the .constructor again, we're perfectly mimicking default prototype behavior. If we don't do that, then instance.constructor will return the first defined .constructor property down the prototype chain, which will be BaseClass. It doesn't really change anything in terms of behavior unless our code actually depends on the constructor property, but it's safer to have it.
As a final note, like others mentioned before I could finally post this answer, you can't just do SubClass.prototype = BaseClass.prototype; because then you wouldn't be able to add methods to the SubClass without adding them to the BaseClass.

I have modified the constructor of a JavaScript what that does imply? [duplicate]

Consider the following code.
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
Why isn't the constructor updated for b and c?
Am I doing inheritance wrong?
What is the best way to update the constructor?
Further, please consider the following.
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
Given that (new c()).constructor is equal to a() and Object.getPrototypeOf(new c()) is a{ }, how is it possible for instanceof to know that new c() is an instance of c?
http://jsfiddle.net/ezZr5/
Okay, let's play a little mind game:
From the above image we can see:
When we create a function like function Foo() {}, JavaScript creates a Function instance.
Every Function instance (the constructor function) has a property prototype which is a pointer.
The prototype property of the constructor function points to its prototype object.
The prototype object has a property constructor which is also a pointer.
The constructor property of the prototype object points back to its constructor function.
When we create a new instance of Foo like new Foo(), JavaScript creates a new object.
The internal [[proto]] property of the instance points to the prototype of the constructor.
Now, the question arises that why doesn't JavaScript attach the constructor property to the instance object instead of the prototype. Consider:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
As you can see the constructor property is just another method of the prototype, like area in the example above. What makes the constructor property special is that it's used to initialize an instance of the prototype. Otherwise it's exactly the same as any other method of the prototype.
Defining the constructor property on the prototype is advantageous for the following reasons:
It's logically correct. For example consider Object.prototype. The constructor property of Object.prototype points to Object. If the constructor property was defined on the instance then Object.prototype.constructor would be undefined because Object.prototype is an instance of null.
It's treated no differently from other prototype methods. This makes the job of new easier since it doesn't need to define the constructor property on every instance.
Every instance shares the same constructor property. Hence it's efficient.
Now when we talk about inheritance, we have the following scenario:
From the above image we can see:
The derived constructor's prototype property is set to the instance of the base constructor.
Hence the internal [[proto]] property of the instance of the derived constructor points to it too.
Thus the constructor property of the derived constructor instance now points to the base constructor.
As for the instanceof operator, contrary to popular belief it doesn't depend on the constructor property of the instance. As we can see from above, that would lead to erroneous results.
The instanceof operator is a binary operator (it has two operands). It operates on an instance object and a constructor function. As explain on Mozilla Developer Network, it simply does the following:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
To put it simply if Foo inherits from Bar, then the prototype chain for the instance of Foo would be:
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
As you can see, every object inherits from the Object constructor. The prototype chain ends when an internal [[proto]] property points to null.
The instanceof function simply traverses the prototype chain of the instance object (the first operand) and compares the internal [[proto]] property of each object to the prototype property of the constructor function (the second operand). If they match, it returns true; and else if the prototype chain ends, it returns false.
By default,
function b() {}
then b.prototype has a .constructor property which is set to b automatically. However, you're currently overwriting the prototype and thus discarding that variable:
b.prototype = new a;
Then b.prototype does not have a .constructor property anymore; it was erased with the overwrite. It does inherit from a though, and (new a).constructor === a, and hence (new b).constructor === a (it is referring to the same property in the prototype chain).
Best to do is to simply setting it manually afterwards:
b.prototype.constructor = b;
You could also make a little function for this:
function inherit(what, from) {
what.prototype = new from;
what.prototype.constructor = what;
}
http://jsfiddle.net/79xTg/5/
constructor is a regular, non-enumerable property of the default value of the prototype property of function objects. Thus, assigning to prototype will lose the property.
instanceof will still work as it does not use constructor, but rather scans the prototype chain of the object for the (current) value of the function's prototype property, ie foo instanceof Foo is equivalent to
var proto = Object.getPrototypeOf(foo);
for(; proto !== null; proto = Object.getPrototypeOf(proto)) {
if(proto === Foo.prototype)
return true;
}
return false;
In ECMAScript3, there's no way to set a constructor property which behaves identically to the built-in one as user-defined properties are always enumerable (ie visible to for..in).
This changed with ECMAScript5. However, even if you set constructor manually, your code still has issues: In particular, it is a bad idea to set prototype to an instance of the parent-'class' - the parent constructor should not be called when the child-'class' is defined, but rather when child-instances are created.
Here's some ECMAScript5 example code for how it should be done:
function Pet(name) {
this.name = name;
}
Pet.prototype.feed = function(food) {
return this.name + ' ate ' + food + '.';
};
function Cat(name) {
Pet.call(this, name);
}
Cat.prototype = Object.create(Pet.prototype, {
constructor : {
value : Cat,
writable : true,
enumerable : false,
configurable : true
}
});
Cat.prototype.caress = function() {
return this.name + ' purrs.';
};
If you're stuck with ECMAScript3, you'll need to use a custom clone() function instead of Object.create() and won't be able to make constructor non-enumerable:
Cat.prototype = clone(Pet.prototype);
Cat.prototype.constructor = Cat;

why instances doesn't inherit property added to constructor function without prototype keyword

in this example a property called 't' is added to speak function.Speak.t=5;when i call speak() it prints the value 5 via another function called show.But when i create new instance of Speak it doesn't inherit the property t.Why is that so??i mean if it is a property of Speak constructor all its instances should inherit it??
<html>
<body>
<script>
function Speak(){
show(Speak.t);
}
Speak.t=5;
function show(v){
console.log('value is : '+v);
}
Speak();
var s1=new Speak();
console.log(s1.t);
</script>
</body>
</html>
"i mean if it is a property of Speak constructor all its instances should inherit it?"
No. Its instances inherit from the constructor's prototype, not the constructor itself. JavaScript is prototype-based, not "Constructor-based". If you are familiar with other OOP languages, Speak.t will be similar to a public static property.
Changing it to Speak.protoype.t = 5 will add the property t: 5 to the prototype which will be inherited to all of its instances:
function Speak(){
show(this.t);
}
Speak.prototype.t = 5;
function show(v){
console.log('value is : '+v);
}
var s1 = new Speak(); //"value is : 5"
console.log(s1.t); //5
Since instances inherit from its constructor's prototype, you can actually achieve class inheritance by doing this:
function SpecialSpeak(){}
SpecialSpeak.prototype = new Speak();
This creates a Speak instance and assign it as the SpecialSpeak's prototype.
new SpecialSpeak() instanceof SpecialSpeak; //true
new SpecialSpeak() instanceof Speak; //true
Since all Speak instances will be updated if its prototype has changed, it will also update SpecialSpeak's prototype and also update all SpecialSpeak's instances.
var s = new SpecialSpeak();
s.v; //undefined
Speak.prototype.v = "text";
s.v; //text
This demonstrates how inheritance works in JavaScript. The chaining of prototypes is sometimes called a "prototype chain".
You might also want to check out this great article about inheritance.
Side note: Since all prototype chains must have a starting point,
Object.prototype instanceof Object; //false
Although Object.prototype is an object, it is the very top prototype (object) that everything* inherits from, therefore it's not an instance of Object. It is the Object!
* Starting from ES5, Object.create is introduced which lets you create objects that doesn't inherit from Object.prototype.
This happens because you don't set internally the value of t. You should instantiate the value of t inside the constructor of Speak like this :
function Speak(){
this.t = 5;
show(this.t);
}
function show(v){
console.log('value is : '+v);
}
Speak();
var s1=new Speak();
console.log(s1.t);
You could also attach the showmethod inside the constructor to access the prototype of it.
var Speak = (function() {
function Speak() {
this.t = 5;
this.show();
}
Speak.prototype.show = function() {
return console.log('value is : ' + this.t);
};
return Speak;
})();
var s1=new Speak();
console.log(s1.t);
When the new operator is called on a constructor function, the JavaScript engine executes a few steps behind the scene:
It allocates a new object inheriting from your constructor function's prototype
It executes your constructor function, passing the newly created object as this
If your constructor function returns an object, then it uses it. Otherwise it uses the this object.
At no time it considers the class properties attached to the constructor function. This is why Speak.t = 5 doesn't create an inherited property.
However, those pieces of code will do:
// By attaching `t` to the prototype
function Speak1() {}
Speak1.prototype.t = 5;
// By attaching `t` to the newly created object
function Speak2() {
this.t = 5;
}
// By returning an object containing `t` (thus overriding the formerly allocated this)
function Speak3() {
return {
t: 5
};
}
DEMO
You can read here for more information.
Since functions are just objects t becomes a property of the function Speak, which is not shared with the instances.
for e.g functions by default get a property called length ( gives arity of the function)
which will not be shared with the instances.
function Speak(){}
var obj = new Speak();
console.log("length" in Speak); // true
console.log("length" in obj); // false
you can see quite clearly the length is not shared with the instances.
In javascript the only way to have a property or a method shared is through the prototype pattern.
Creating a property this way, makes it behave like a static variable on Speak

Prototype keyword in Javascript

What is prototype property, and why is it necessary? So far, I have learnt that this provides public access to more intrinsic, and private prototype of the object; is that correct?
Also, what's the difference between following statements?
MyConstructor.age = 30;
MyConstructor.prototype.age = 30;
In short, I need a better understanding of keyword prototype.
Thanks
"Prototype" is something that plays a role in objects.
In Javascript, everything is an object. Every object has a kind, and thus inherits the prototype of that kind.
For example, take a simple array: var a = []. You can make operations with it, like a.push(10). Where does this push method come from? From the prototype of Array object, which a is.
You can add your own methods to Array objects just by defining them in the prototype object. For example:
Array.prototype.sortNum = function() {this.sort(function(a, b) {return a - b});};
This way you can do something like a.sortNum() with all arrays, even the ones created before you defined the sortNum method.
(Note: for compatibility reasons, it's usually not recommended to extend the prototype of native objects like Arrays. But this particular example is usually a welcome addition, as well as normalizing methods like map and forEach for older browsers.)
(Just never ever extend Object.prototype! Unless you don't care to mess up for...in statements, the in operator and these sort of cases.)
If you want to define your own classes, like the name MyConstructor suggests, you'll have to define its prototype to define the methods for all the instances of that class:
function MyConstructor(name) {this.name = name};
MyConstructor.prototype = {
print: function() {return this.name;}
};
var mc = new MyConstructor("foo");
alert(mc.print()); // alerts "foo"
You can define more than just functions in prototypes, too:
MyConstructor.prototype.age = 30;
alert(mc.age); // alerts 30
Watch out when you do this to define "default" object values, because changing it may cause a change in all instances of that class.
But this comes handy with Object.defineProperty:
Object.defineProperty(MyConstructor.prototype, "wholeString", {
get: function() {return this.name + "=" + this.age;},
set: function(v) {this.name = v.substring(3);}
});
alert(mc.wholeString); // alerts "foo = 30"
(Unfortunately, IE<9 allows this only for DOM objects...)
When you define MyConstructor.age = 30 instead, what you're actually doing is defining a member of the function MyConstructor, so mc.age would be undefined. Every instance of MyConstructor inherits the methods and members defined in MyConstructor.prototype, not the ones of the function MyConstructor.
There's much more to say, actually. Objects can be of a subclass of another class, thus inheriting the prototype of the superclass, too. For example, document.body is an instance of HTMLBodyElement, which is a subclass of HTMLElement, which is a subclass of Element and so on, until you get Object as the upmost superclass. So, document.body inherits all the methods defined in the prototype of HTMLBodyElement, HTMLElement, Element and Object. This is called the prototype chain.
Doing the same with custom objects is a bit tricky:
function Class() {};
Class.prototype.foo = function() {alert("foo");};
function Subclass() {};
Subclass.prototype = new Class();
Subclass.prototype.bar = function() {alert("bar");};
var a = new Class(), b = new Subclass();
a.foo(); // alerts"foo"
a.bar(); // throws an error
b.foo(); // alerts "foo"
b.bar(); // alerts "bar"
a instanceof Class; // true
a instanceof Subclass; // false
b instanceof Class; // true
b instanceof Subclass; // true
In JavaScript, function objects have a built-in .prototype property. The value of this property is an object. If the function is used as a constructor, the resulting instances inherit from that "prototype" object.
Example:
var Dog = function () {}; // the constructor function
Dog.prototype.bark = function () {}; // adding a method to Dog.prototype
var dog1 = new Dog; // creating a new instance
dog1.bark(); // the instance inherits the "bark" method from Dog.prototype
Note that the .prototype property (of function objects) is not the same as the [[Prototype]] internal property. All objects contain the latter. It's an internal reference to an object's prototype. (In the above example, the dog1 object's [[Prototype]] refers to Dog.prototype.) On the other hand, only function objects have a built-in .prototype property (which makes sense since only function objects can be used as constructors).
var foo = function () {};
foo.bar = 5;
foo.prototype.foobar = 10;
var x = new foo();
x.bar; // undefined
x.foobar; // 10
Edit: Also, you can then do
foo.prototype.foobar = 20;
x.foobar; // 20

Categories

Resources