JavaScript之实现继承一

console.log("----------------------------------------实现继承----------------------------------------");
//继承(Inheritance)是一种在新对象上复用现有对象的属性的形式。这有助于避免重复代码和重复数据。在JavaScript中,继承原理和其他的面向对象语言略有不同。
console.log("-----------尝试实现原型继承------------");
function Person() {}
//通过构造函数及其原型,创建一个具有dance方法的Person类型
Person.prototype.dance = function () {};

//定义NewNinja构造函数
function NewNinja() {}
//试图复制Person的原型方法dance到NewNinja的原型上。
NewNinja.prototype = {dance: Person.prototype.dance}

const newNinja = new NewNinja();
if (newNinja instanceof NewNinja) {
  console.log("newNinja receives functionality from the Ninja prototype");
}
if (newNinja instanceof Person) {
  console.log("... and the Person prototype");
}
if (newNinja instanceof Object) {
  console.log("... and the Object prototype");
}

由于函数原型是对象类型,因此有多种复制功能(如属性或方法)可以实现继承的方法。在本例中,我们先定义Person与NewNinja。显然NewNinja是一个Person,我们希望NewNinja能够继承Person属性。我们试图将Person原型上的dance方法复制到NewNinja原型的同名属性上。

通过执行测试发现:虽然我们已经教会了 newNinja dance,但是无法使得newNinja 成为成为真正的Person类型。我们对newNinja 进行模拟Person的dance方法,但是newNinja 仍然不是真实的Person类型。这不是真正的继承——仅仅是复制。

所以可以知道:这种方法是无效的继承,因此我们还需要将每个Person的属性单独复制到NewNinja的原型上。这种办法没有 实现继承。

我们真正想要实现的一个完整的原型链,在原型链上,NinjaTest继承自Person,Person继承自Mammal,Mammal继承自Animal,以此类推,一直推到Object。创建这样的原型链的最佳方案是一个对象的原型直接是另一个对象的实例:

SubClass.prototype = new SuperClass();

例如:

Ninja.prototype = new Person();

因为SubClass实例的原型是SuperClass的实例,SuperClass实例具有SuperClass的全部属性,SuperClass实例也同时具有一个指向超类的原型。

console.log("-----------------------使用原型实现继承---------------------------");
function Person() {

}
Person.prototype.dance = function () {};

function NinjaTestInherit() {}
//通过将NinjaTest的原型赋值给Person实例,实现NinjaTestInherit继承Person.
NinjaTestInherit.prototype = new Person();

const ninjaTestInherit = new NinjaTestInherit();
if (ninjaTestInherit instanceof NinjaTestInherit) {
  console.log("ninjaTestInherit receives functionally from the NinjaTestInherit proptype");
}
if (ninjaTestInherit instanceof Person) {
  console.log("... and the Person proptype");
}
if (ninjaTestInherit instanceof Object) {
  console.log("... and the Object proptype");
}
if (typeof ninjaTestInherit.dance === "function") {
  console.log("... and can dance!");
}

 

上述代码中,使用Person的实例作为NinjaTestInherit的原型。测试发现这种方式成功实现了继承。

从上述log可以发现,当定义一个Person函数时,同时也创建了Person原型,该原型通过其constructor属性属性引用函数本身。正常来说,我们可以使用附加属性扩展Person原型。在上面的代码中,在Person的原型上扩展了dance方法,因此每个Person的实例对象也都有dance方法:

function Person() {}

Person.prototype.dance = function () {};

然后定义一个NinjaTestInherit。该函数的原型也具有一个constructor属性指向函数本身:

function NinjaTestInherit() {}

接下来,为了实现继承,将NinjaTestInherit的原型赋值为Person的实例。现在,每当创建一个新的NinjaTestInherit对象时,新创建的NinjaTestInherit对象将设置为NinjaTestInherit的原型属性所指向的对象,即Person实例:

function NinjaTestInherit() {}

//通过将NinjaTest的原型赋值给Person实例,实现NinjaTestInherit继承Person.

NinjaTestInherit.prototype = new Person();

const ninjaTestInherit = new NinjaTestInherit();

尝试通过NinjaTestInherit对象访问dance方法,JavaScript运行时将会首先查找NinjaTestInherit对象本身。由于NinjaTestInherit本身不具有dance方法,接下来搜索NinjaTestInherit对象的原型即Person对象。Person对象也不具有dance方法,所以再接着查找Person对象的原型,最终找到了dance方法。这就是JavaScript中实现继承的原理!

 

上图为NinjaTestInherit的原型构造器赋值为Person的实例,实现NinjaTestInherit继承Person。

重要提示:通过执行instanceof操作符,可以判定函数是否继承原型链上的对象功能。

注意点:强烈不建议使用的,就是直接使用Person的原型对象作为NinjaTestInherit的原型对象,如NinjaTestInherit.prototype=Person.protoype。这样做会导致在Person原型上所发生的所有变化都被同步到NinjaTestInherit原型上(Person原型与NinjaTestInherit原型是同一个),一定会有不良作用。

这种原型实现继承的方式的骨作用好的一面是,所有继承函数的原型将实时更新。从原型继承的对象总可以访问当前原型属性。

 

参考《JavaScript忍者秘籍》

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/84889882