JS红宝书笔记 8.3 继承

发布于:2025-06-20 ⋅ 阅读:(19) ⋅ 点赞:(0)

原型链

原型链是ES的主要继承方式,其基本思想就是通过原型继承多个引用类型的属性和方法

每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。如果原型是另一个类型的实例,那就意味着这个原型本身有一个内部指针指向另一个原型,相应的另一个原型也有一个指针指向另一个构造函数,这样就在实例和原型之间构造了一条原型链

原型链扩展了原型搜索机制,在读取实例上的属性时,首先会在实例上搜索这个属性,如果没找到,则会继承搜索实例的原型,在通过原型链实现继承之后,搜索就可以继承向上,搜索原型的原型,对属性和方法的搜索会一直持续到原型链的末端

默认情况下,所有引用类型都继承自Object,这也是通过原型链来实现的,任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype

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

  • 第一种方式是使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true。

  • 第二种方式是使用isPrototypeOf()方法,原型链中的每个原型都可以调用这个方法,只要原型链中包含这个原型,这个方法就返回true

子类有时候需要覆盖父类的方法,或者增加父类没有的方法,为此,这些方法必须在原型复制之后再添加到原型上

以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链

原型链的主要问题出现在原型中包含的引用值会在所有实例间共享,在使用原型实现继承时,原型实际上变成了另一个类型的实例,这意味着原先的实例属性变成了原型属性

原型链的第二个问题是,子类型在实例化时不能给父类型的构造函数传参


盗用构造函数

基本原理:在子类构造函数中调用父类的构造函数,可以使用apply()和call()方法以新创建的对象为上下文执行构造函数

相比于使用原型链,盗用构造函数的一个优点就是可以在子类构造函数中向父类构造函数传参

盗用构造函数的缺点,也是使用构造函数模式自定义类型的问题:必须在构造函数中定义方法,因此函数不能重用,此外,子类也不能访问父类原型上定义的方法,因此所有类型只能使用构造函数模式


组合继承

综合了原型链和盗用构造函数,将两者的优点集中了起来,基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性,这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性


原型式继承

function object(o){
    function F(){}
    F.prototype = o
    return new F()
}

这个object()函数会创建一个临时构造函数,将传入的对象赋值给这个构造函数的原型,然后返回这个临时类型的一个实例,本质是,object()是对传入的对象执行了一次浅复制

适用于这种情况:你有一个对象,想在它的基础上再创建一个新对象。你需要吧这个对象先传给object(),然后再对返回的对象进行适当修改

ES5通过Object.create()方法将原型式继承的概念规范化了,这个方法接受两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(可选),第二个参数与Object.defineProperties()的第二个参数一样:每个新增属性都通过各自的描述符来描述。以这种方式添加的属性会遮蔽原型对象上的同名属性

原型式继承非常适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合,但属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的


寄生式继承

寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象

寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景,通过寄生式继承给对象添加函数会导致函数难以重用,与构造函数模式类似


寄生式组合继承

组合式继承存在效率问题,父类构造函数始终会被调用两次:一次实在创建子类原型时调用,另一次是在子类构造函数中调用。本质是,子类原型最终是要包含超类对象的所有实例属性,子类构造函数只要在执行时重写自己的原型就行了

寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路是不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本,说到底就是使用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类原型。


网站公告

今日签到

点亮在社区的每一天
去签到