摘要:冴羽的博客学习对象的继承
原型链继承
通过原型链继承时不可以使用字面量创建原型方法,因为这样会重写原型链
1 | function Person() { |
注意:
1.实例化子类 Child 时,无法向父类 Person 传参
2.所有实例共享同一个原型对象,因而一定要区分修改属性的主体是实例对象还是原型对象。一般使用等号 = 赋值是为实例自身添加或修改属性,实例添加的自身属性会比原型上的属性先查询到,可以遮盖原型上的同名属性、方法。但有时候修改的是原型上的属性,特别是引用类型的属性,比如上面调用的 push 方法,其修改的就是原型上的数据,这会导致所有实例共享的原型数据发生变化
借用构造函数(经典继承)
原理:在子类型构造函数的内部调用父类型构造函数。call、apply 方法可以实现(模拟实现call、applay、bind和new)
1 | function Person(age) { |
注意:
1.引用类型的属性不会被所有实例共享
2.实例化子类 Child 时,可以向父类 Person 传参
3.方法都在构造函数中定义,每次创建实例都会创建一遍方法,每个方法都是一个独立的对象,这会出现大量功能重复的函数对象,浪费空间
组合继承
原型链继承 + 经典继承,原理:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承
1 | function Person(age) { |
注意:通过在原型上定义方法实现了函数复用,又保证每个实例都有自己的属性,是 js 中最常用的继承方式
原型式继承
借助原型基于已有的对象创建对象,同时不必因此自定义类型。是 Object.create 的模拟实现,或者直接使用 Object.create 方法。
1 | function _create(o) { |
注意:
1.原型上的属性会共享,修改属性时的表现与原型链继承相似,一定要区分修改属性的主体是实例对象还是原型对象。一般的赋值是修改实例对象,但引用类型属性的修改有可能是操作原型对象
寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,再返回对象。整个过程就是封装了原型式继承,然后又给生成的实例添加属性、方法。
1 | function _create(o) { |
注意:
1.不能复用函数,每次创建对象都会创建一遍所有方法,造成空间浪费
2.修改属性时的表现与原型链继承相似,一定要区分修改属性的主体是实例对象还是原型对象。一般的赋值是修改实例对象,但引用类型属性的修改有可能是操作原型对象
寄生组合式继承
寄生组合式继承是实现基于类型继承的最有效方式。只会调用一次父类型,避免了在父类型原型上创建多余的属性,同时原型链还保持不变。其本质上是使用寄生式继承来继承父类型的原型,然后再将结果指定给子类型的原型。原本组合式继承的原型链是 实例.__proto__ 指向 父类.prototype,寄生组合式继承的原型链是 实例.__proto__ 指向 寄生中间对象.prototype,寄生中间对象.__proto__ 再指向 父类.prototype,中间多了个寄生对象,这样修改子类的原型方法也不会影响到父类,因为中间还有一个寄生对象,子类修改原型属性其实是修改的寄生对象的属性。
1 | function Parent(name) { |
封装一下:
1 | function object(o) { |