问题
I was looking at this video explanation(https://www.youtube.com/watch?v=qMO-LTOrJaE) of JS prototypal inheritance. There's something I don't understand. Let me explain
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom); //prints Animalia //however, members in parent's prototype is accessible
But as soon as you add the following line to the Grizzly constructor,
var Grizzly = function(type){
Bear.call(this, type); //ADDED
this.species = 'Brown Bear';
}
you're able to access everything from the parent, not just it's prototype
console.log(grizzly1.hasFur); //prints true
console.log(grizzly1.kingdom); //prints Animalia
However, inheriting in the below fashion, gives the child access to everything in the parent even without the line //Bear.call(this) in the Child constructor.
Grizzly.prototype = new Bear();
So it truly inherits everything this way. Can someone explain what's this behavior and why it happens ?
Also what are the different ways of inheriting in JavaScript. Which one is the best to use considering best practices and why.
回答1:
There's something I don't understand. Let me explain
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom); //prints Animalia //however, members in parent's prototype is accessible
In the code snippet shared above, grizzly1.hasFur
is undefined
as the constructor function for Bear
is not yet executed. The line Grizzly.prototype = Object.create(Bear.prototype);
just inherits the parent prototypal methods and properties.
But as soon as you add the following line to the Grizzly constructor,
var Bear = function(type) { //PARENT
this.type;
this.hasFur = true;
}
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type) { //CHILD
Bear.call(this, type); //ADDED
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(Bear.prototype); //INHERITING FROM PARENT
var grizzly1 = new Grizzly('grizzly');
console.log(grizzly1.hasFur); //prints undefined //members in parent's constructor not accessible
console.log(grizzly1.kingdom);
grizzly1.hasFur
is now true
because now within the constructor function of grizzly
, the constructor class for Bear
is invoked changing its context using a call
. The this. hasFur
gets its true
value assigned in this operation as here due to the changed context, this
now refers to the instance of grizzly
.
However, inheriting in the below fashion, gives the child access to everything in the parent even without the line //Bear.call(this) in the Child constructor. Grizzly.prototype = new Bear();
What happens here is, a new instance of the Bear class is created. Now any instance of the class Bear can have access to the prototypal methods and internal properties defined while instantiating the constructor class i.e. function Bear
. Now after the instance being created, this gets assigned to the prototypal chain of Grizzly
. So any new instance of Grizzly
not only access the internal properties of Grizzly
, but also behaves as a new instance of the Bear class.
Also what are the different ways of inheriting in JavaScript
I would definitely suggest you to study design patterns. You can google out different books for it. I loved reading JavaScript: The Good Parts and Learning JavaScript Design Patterns. You might love some other books for clearing up your fundamentals. There are few countable things in Javascript like these, closures, etc., which needs crystal clear conceptions.
Which one is the best to use considering best practices and why.
The best practice in prototypal inheritance ,I prefer,is:
In the constructor class say A
function A () {
this.privateProp = something;
}
A.prototype.public = something;
So see declare only those properties and methods inside the constructor class, which you wanna keep private. Rest keep it exposed in prototype chain.
Hope this helps.
回答2:
Check this out:
var Bear = function(type){ //PARENT
this.type;
this.hasFur = true;
}
alert(new Bear().hasFur);
See how this does gives you true
in the alert box. Think, why is this working, and not for your example?
Thought about it?
It's because in this code:
var Bear = function(type){ //PARENT
this.type;
this.hasFur = true;
}
You're assigning the function to Bear
, so it's accessible by new Bear()
not Bear.prototype
. This will work:
Bear.prototype.kingdom = 'Animalia'; //ASSIGNING TO PARENT'S PROTOTYPE
var Grizzly = function(type){ //CHILD
this.species = 'Brown Bear';
}
Grizzly.prototype = Object.create(new Bear()); // Modified line
var grizzly1 = new Grizzly();
alert(grizzly1.hasFur); // Prints true now.
alert(grizzly1.kingdom);
来源:https://stackoverflow.com/questions/38819688/javascript-prototypal-inheritance-truly-understanding-the-concept