javascript prototypical inheritance confused - javascript

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.

Related

How function resolution in prototype chain will work for Object.prototype as constructor

I am referring to this web archive of an article originally on Helephant.com, to learn how Javascript resolves functions in the prototype chain when called on objects.
The article quotes,
If the object doesn’t have the method set directly on it, javascript then looks for a Constructor function that created the object. Javascript checks the constructor’s prototype property for the method.
In the following code, if you check rufus.constructor is the global Object() constructor, so will JS directly check the global Object() since rufus.constructor is Object() or as per the article quote above it will first look at the constructor and then find the prototype property and so on.. How will JS resolve the function (rufus.toString). I am quite confused with this.
//PET CONSTRUCTOR
function Pet(name, species, hello)
{ this.name = name;
this.species = species;
this.hello = hello; }
Pet.prototype = {
sayHello : function(){
alert(this.hello);
}
}
//CAT CONSTRUCTOR
function Cat(name, hello, breed, whiskerLength)
{ this.name = name;
this.hello = hello;
this.breed = breed;
this.whiskerLength = whiskerLength;}
Cat.prototype = new Pet();
var rufus = new Cat("rufus", "miaow", "Maine Coon", 7);
rufus.toString;
If the object doesn’t have the method set directly on it, javascript
then looks for a Constructor function that created the object.
Javascript checks the constructor’s prototype property for the method.
The wording is confusing. The JavaScript looks up the prototype chain through __proto__ and does not use constructor property. They mentioned Constructor because usually, that is how objects get their prototype - through Constructor.prototype property. But that is not always true. You can set the prototype like this:
var rufus2 = Object.create(new Pet());
Object.getPrototypeOf(rufus) === Object.getPrototypeOf(rufus2); // true
Regarding how the toString method is resolved:
rufus.hasOwnProperty('toString'); // false -> go up
(new Pet()) rufus.__proto__.hasOwnProperty('toString'); // false -> go up
({sayHello :...}) rufus.__proto__.__proto__.hasOwnProperty('toString'); // false -> go up
(Object.prototype) rufus.__proto__.__proto__.__proto__.hasOwnProperty('toString'); // true
function Person () { }
Person.prototype.sayName = function () { };
var bob = new Person();
console.log(bob.sayName === Person.prototype.sayName); // true
console.log(bob.constructor.prototype.sayName === Person.prototype.sayName); // true
console.log(bob.__proto__.sayName === Person.prototype.sayName); // true
console.log(bob.constructor === Person); // true
console.log(bob.__proto__ === Person.prototype); // true
Those are your relationships.
If a property / function can not be found on an object, it goes up the __proto__ chain to find what it's looking for. In older browsers, __proto__ was not accessible to JS devs, but was still the object that the browser/Node used behind the scenes, to refer to the Constructor.prototype property.
PS: try not to use deep hierarchy in JS. That is a path of many tears. Deep hierarchies cause pain in other class-based languages, but are misery in JS, where often a function would suffice.

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

Confused about Douglas Crockford's object function

I know Crockford has a famous object function for inheritance in JavaScript:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
But I am confused, after the line F.prototype = o, why he doesn't he reset the F.prototype's constructor, like this:
F.prototype.constructor = F
Isn't that common practice?
Isn't that common practice?
Only when your're creating subclasses (constructor functions with prototypes inheriting from other prototypes).
But that's not the purpose of this code, which basically Object.create. It takes the part of creating the object which inherits from another object, nothing else. The F constructor function is only intermediate and not supposed to be exposed.
F.prototype = o;
why he doesn't he do F.prototype.constructor = F?
Because that would change o itself. The aim is only to create a new object. Notice that it returns an instance of the intermediate constructor, not the constructor itself.
Where would the constructor be set (if needed)? On the new object that is instantiated by object:
function inherit(chd, par) {
chd.prototype = object(par.prototype);
chd.prototype.constructor = chd;
}
function Foo() {}
function Bar() {}
inherit(Foo, Bar);
/* Because of overwriting `constructor`: */
Foo.prototype.constructor === Foo
(new Foo).constructor === Foo
/* Because of the prototype chain: */
new Foo instanceof Bar // true, because
Foo.prototype instanceof Bar // true
Since you are using an instance of F as prototype object itself, there is no benefit in setting the constructor property.
For example:
function Foo() {}
function Bar() {}
Bar.prototype = object(Foo.prototype);
Bar.prototype.constructor = Bar;
So now Bar.prototype is an instance of F. We assigned the constructor property to that instance which would shadow the constructor property assigned to F.prototype. So why bother assigning it in the first place?
Generally speaking the constructor property has no significance in JavaScript, but it may be useful in your own code. I.e. your code might depend on the correct value of constructor. But in the object function, F is just a temporary constructor and object just replicates the functionality of Object.create, which is supported in newer browsers. I cannot think of a use case where you want a reference to F in your code.

Trying to understand inheritance in JavaScript -- what's going on here?

Why does this say "Animal" instead of "kitty"?
// create base class Animal
function Animal(animalType) {
this.type = animalType;
this.sayType = function () {
alert(this.type);
};
}
// create derived class Cat
function Cat(myName) {
Animal.call(this, "cat"); // cat calls the Animal base class constructor
this.name = myName;
this.sayName = function () {
alert(this.name);
};
}
Cat.prototype = Object.create(Animal); // set Cat's prototype to Animal
// instantiate a new instance of Cat
var cat = new Cat("kitty");
cat.sayName();
cat.name = "lol";
cat.sayName();
http://jsfiddle.net/dgcoffman/MguUA/5/
Object.create(Animal); // set Cat's prototype to Animal
Yes, but to the Animal constructor function (or, to be exact: to a new object inheriting from that function object - check the docs for Object.create). That's hardly what you want - and explains your curious result of saying "Animal", as that's the Animal function's name property.
Instead, you want to build a prototype chain, so that cat instances inherit from Cat.prototype which inherits from Animal.prototype (which inherits from Object.prototype):
Cat.prototype = Object.create(Animal.prototype);
Also, for prototypical inheritance, you should but the sayName and sayType methods on the prototype object (and only once):
Animal.prototype.sayType = function() {
alert(this.type);
};
Cat.prototype.sayName = function() { // after creation of that object, of course
alert(this.name);
};
You're calling Object.create() in a way that does something different than what I bet you think it does. Try this change:
Cat.prototype = Object.create(new Animal);
The Object.create() function expects its first argument to be the object to be used as the prototype for the returned object. When you pass in the function name "Animal", that means you want the prototype object to be that function object, and not an object constructed by the function.
edit — Bergi's answer involving the direct use of the Animal prototype probably makes more sense, though from what you posted there isn't an Animal prototype object with anything interesting on it. Perhaps that's elsewhere in your code, or will be added later. Anyway if it does exist it's better to do as in his answer.
Since your "Cat" constructor is picking up the "sayType" property from the Animal constructor directly, it's not clear what you're trying to do by setting the Cat prototype.

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