js函数继承-原型链详解

1. 继承

继承是面向对象编程中讨论最多的话题。很多面向对象语言都支持两种继承:接口继承和实现继承。前者只继承方法签名,后者继承实际的方法。接口继承在 ECMAScript 中是不可能的,因为函数没有签名。实现继承是 ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的。

2. 原型链

ECMAScript 把原型链定义为 ECMAScript 的主要继承方式。其基本思想就是通过原型继承多个引用类型的属性和方法。
重温一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。如果原型是另外一个类型的实例呢?
看以下案例:

// 创建Animal
function Animal() {
   
  this.name = 'animal';
}
Animal.prototype.getAnimalName = function () {
   
  console.log(this.name + 'getAnimalName');
}
// 创建Dog
function Dog() {
   
  this.name = 'dog';
}
// Dog继承自Animal  将Animal的实例赋值给Dog的原型对象,相当于将Animal的实例中的__proto__赋值给了Dog的原型对象
// 如此 Dog原型对象 就能通过 Animal 对象的实例中的[[prototype]](__proto__) 来访问到 Animal原型对象 中的属性和方法了。
Dog.prototype = new Animal();
// 不建议使用Dog.prototype.__proto__=== Animal.prototype,因为双下划线的属性是js中的内部属性,各个浏览器兼容性不一,不建议直接操作属性,ES6中提供了操作属性的方法可以实现。
console.log(Dog.prototype.__proto__ === Animal.prototype );
// 在使用原型链继承的时候,要在继承之后再去原型对象上定义自己所需的属性和方法
Dog.prototype.getDogName = function () {
   
  console.log(this.name + 'getDogName');
}
var d1 = new Dog();
d1.getAnimalName()
d1.getDogName()

这个案例,分别定义了两个类型Animal和Dog。
Animal有自己的构造函数和原型,Animal原型里定义了一个方法getAnimalName();Dog也有自己的构造函数和原型。
两个类型不同的是,**Animal原型的实例赋值给了Dog的原型对象。也就是说Animal的实例对象就是Dog的原型对象,Dog的原型对象就是Animal的实例,两者互相指向。**这意味着 Animal 实例可以访问的所有属性和方法也会存在于 Dog. prototype。这样实现继承之后,代码紧接着又给Dog.prototype,也就是这个 Animal 的实例添加了一个新方法。最后又创建了 Dog 的实例并调用了它继承的 getAnimalName方法。
看以下图片案例分析原型链:
在这里插入图片描述
这个案例中实现继承的关键,是 Dog 没有使用默认原型,而是将其替换成了一个新的对象。这个新的对象恰好是 Animal 的实例。这样一来,Dog的实例不仅能从 Animal 的实例中继承属性和方法,还与Animal的原型挂上了钩。
注意,由于 Dog.prototype 的 constructor 属性被重写为指向Animal,所以 d1.constructor 也指向 Animal,想要指回Dog可以修改Dog.prototype.constructor。
**原型搜索机制:**读取实例上的属性时,首先会在实例上搜索这个属性。如果没找到,则会继承搜索实例的原型,这就是原型搜索机制。在通过原型链实现继承之后,搜索就可以继承向上,搜索原型的原型。

2.1 默认的原型链

实际上,原型链中还有一环。即默认情况下,所有应用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype.这也是为什么自定义类型能够继承包括 toString()、valueOf()在内的所有默认方法的原因。因此前面的例子还有额外一层继承关系。
在这里插入图片描述
Dog 继承 Animal,而 Animal 继承 Object。在调用 d1.toString()时,实际上调用的是保存在Object.prototype 上的方法。

2.2 原型与继承关系

原型与实例的关系可以通过两种方式来确定。

  1. 第一种方式是使用 instanceof 操作符

instanceof:用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

在上面的案例中:

console.log(d1 instanceof Object);  //true
console.log(d1 instanceof Animal)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值