Javascript 原型继承 - 真正理解这个概念

Javascript Prototypal Inheritance - Truly understanding the concept

我在看这个JS原型继承的视频讲解(https://www.youtube.com/watch?v=qMO-LTOrJaE)。 有件事我不明白。让我解释一下

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

但是只要将以下行添加到 Grizzly 构造函数中,

var Grizzly = function(type){
  Bear.call(this, type); //ADDED
  this.species = 'Brown Bear';
}

您可以访问父级的所有内容,而不仅仅是它的原型

console.log(grizzly1.hasFur);  //prints true
console.log(grizzly1.kingdom); //prints Animalia

但是,以下面的方式继承,即使在 Child 构造函数中没有 //Bear.call(this) 行,子级也可以访问父级中的所有内容。

Grizzly.prototype = new Bear();

所以它真的以这种方式继承了一切。有人可以解释这是什么行为以及为什么会发生吗?

另外 JavaScript 中有哪些不同的继承方式。考虑最佳实践和原因,哪一个是最好的。

看看这个:

var Bear = function(type){ //PARENT
  this.type;
  this.hasFur = true;
}

alert(new Bear().hasFur);

看看这个如何在警告框中给你true。想一想,为什么这是有效的,而不是你的例子?

想过吗?

这是因为在这段代码中:

var Bear = function(type){ //PARENT
  this.type;
  this.hasFur = true;
}

您将函数分配给 Bear,因此 new Bear() 而不是 Bear.prototype 可以访问它。这将起作用:

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); 

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

在上面分享的代码片段中,grizzly1.hasFurundefined,因为 Bear 的构造函数尚未执行。 Grizzly.prototype = Object.create(Bear.prototype); 行只是继承父原型方法和属性。

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 现在是 true 因为现在在 grizzly 的构造函数中,Bear 的构造函数 class 被调用并使用call。由于上下文已更改,this. hasFur 在此操作中获得其分配的 true 值,this 现在指的是 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();

这里发生的是,创建了 Bear class 的一个新实例。现在 class Bear 的任何实例都可以访问在实例化构造函数 class 时定义的原型方法和内部属性,即 function Bear。现在在创建实例后,它被分配给 Grizzly 的原型链。因此 Grizzly 的任何新实例不仅可以访问 Grizzly 的内部属性,而且还可以作为 Bear class.

的新实例

Also what are the different ways of inheriting in JavaScript

我肯定会建议你学习设计模式。你可以 google 出不同的书给它。我喜欢阅读JavaScript:好的部分学习JavaScript 设计模式。您可能会喜欢其他一些书籍来清理您的基础知识。 Javascript 中很少有像这些、闭包等可数的东西,需要crystal 清晰的概念。

Which one is the best to use considering best practices and why.

原型继承的最佳实践,我更喜欢,是: 在构造函数中 class 说 A

function A () {
   this.privateProp = something;
}
A.prototype.public = something;

因此,请参阅仅在构造函数 class 中声明那些您想保密的属性和方法。剩下的让它暴露在原型链中。

希望对您有所帮助。