Javascript Prototypical Inheritance Confused
Solution 1:
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:
functionBaseClass() {
}
functionSubClass() {
BaseClass.call(this);
}
SubClass.prototype = BaseClass.prototype;
SubClass.prototype.constructor = SubClass;
SubClass.prototype.subClassFunction = function(){
console.log("Added this to SubClass");
}
var baseObj = newBaseClass();
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.
Solution 2:
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
Solution 3:
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 :
functionBaseClass() {
}
functionSubClass() {
}
varBaseClass = newBaseClass();
varSubClass = newSubClass();
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
.
Solution 4:
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.
Post a Comment for "Javascript Prototypical Inheritance Confused"