继承
前言
JavaScript是单继承的,只能继承一个父类
原型链继承
- 定义: 子类构造函数的prototype指向父类创建出来的对象
function Person(name,age){
this.name = name
this.age = age
this.run = function(){ return 'run' }
}
function Student( stNo ){
this.stNo = stNo
}
Student.prototype = new Person('nano',18)
const stu1 = new Student(11)
let run = stu1.run()
console.log(run) --> run
- 缺点
- 继承的属性无法打印出来,因为是原型属性[[prototype]], 不可枚举
- 如果父类里的值是引用类型,某个子类在修改该引用类型的值时其它子类也会被影响
- 声明子类的时候无法传递参数直接赋值给继承父类的属性,必须得在父类声明时传递
借助构造函数继承
- 在原型链继承的基础上借用构造函数继承
function Person(name,age){
this.age = age
this.name = name
this.say = function(){ console.log(this.name) }
}
function Student(name,age,stNo){
/*
借助构造函数,指定this的绑定,这样实现子类传递参数,父类统一接收
在子类的函数this中添加了属性,这样就可以打印出来
每次调用子类,都会独有this,这样解决了引用类型指针共享的问题
*/
Person.call(this,name,age)
this.stNo = stNo
this.run = function(){ console.log( 'run') }
}
Student.prototype = new Person()
const stu = new Student('nano', 19, '05')
console.log( stu )
- 优点: 解决了原型链继承的全部问题
- 缺点:
(1) 父类函数至少被调用了两次
(2) 子类的原型对象[[prototype]]上会多一些没有必要存在的属性
寄生式继承(针对于对象)
- 定义: 原型继承结合工厂模式
// 父类 let personObj = { running(){ console.log('run') } } // 工厂函数 function createStu(personObj,name){ // 创建一个原型指向父类的子类 let obj = Object.create(personObj) obj.name = name obj.say = function(){} return obj } let stu1 = createStu(personObj, 'nano') let stu2 = createStu(personObj, 'roily')
- 缺点:
(1) 重复创建函数
(2) 无法知道是什么类型的类
寄生组合式继承(最终方案)
- 定义: 将借助构造函数继承和寄生式继承结合
// 为了方法复用,往往会封装一个工具函数 function inherit(parent,child){ child.prototype = Object.create(parent.prototype) Object.defineProperty(child.prototype,'constructor',{ value:child, configure:true, enumerable:false, writable:true }) } function Parent(name,age){ this.name = name this.age = age this.say = function(){} } fcuntion Child(name,age,sno){ Parent.call(this,name,age) this.sno = sno this.study = function (){} } /* 没有进行函数复用封装 // 寄生式继承,Object.create用来创建一个原型[[prototype]]指向父类的空对象 Child.prototype = Object.create(Parent.prototype) --> createObj(Parent.prototype) [createObj函数在下方] // 将寄生式继承的名称由父类改为子类,实际就是更改显示原型上constructor函数的指向 Object.defineProperty(Child.prototype,'constructor',{ value:Child, // constructor 指向构造函数 configure:true, enumerable:false, writable:true }) */ // 进行函数复用封装 inherit(Parent,Child) Child.prototype.eating = function( ){} // 如果不适用Object.create()函数该如何实现寄生式继承? function createObj(o){ // 声明一个新函数 function Foo(){} // 将该函数的显示原型指向传进来的对象 foo.prototype = o // 返回new出来的对象,该对象的原型指向Foo的prototype,指向o reutrn new Foo() }
注意: ES6的class继承就是该模式的语法糖
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!