本文已参与「新人创作礼」活动,一起开启掘金创作之路。
组合式继承
组合 就是两方面都各做一次,缺点是 所谓"两次执行"父类的构造函数
第一次是new实例化 用于创建子类的原型对象 目的是共享方法
第二次是单纯执行 用于将父类的属性赋予子类的实例 目的是拥有属性
父类构造函数 可想象为 形如this.key = val,
let parent = function(name) {
// 父类型的自有属性
this.name = name;
this.hobbies = ['tennis','music','photography']
}
而子类构造函数除了往this上添加属性外,还通过call让自己的this执行父类构造函数 把父类属性加到自己身上
let son = function(name,sex) {
//构造函数式继承父类属性,这里是第二次调用父类构造函数
parent.call(this, name);
// 添加子类自己的私有属性
this.sex = sex;
}
在new子类构造函数得到子类实例之前,为了共享原型方法,需要得到一个父类实例 作为子类原型对象
son.prototype = new parent(); 这是首次调用父类构造函数 作为子类原型对象;
son.prototype.constructor = son;并且让这个新的原型对象链接到子类构造函数;
son.prototype.getsex = function () { console.log(this.sex)} 此后可以添加子类自己的方法
梳理:定义子类构造函数(内部是父类call this)->将构造函数原型对象用父类实例替换 ->原型对象的cst指回子类构造函数(此时可以向原型对象上添加共享方法)->创建子类实例(此时父类构造函数将私有属性赋予了子类实例)
优点是子类实例不会修改父类引用属性,缺点是两次执行父类构造函数
原型式继承
场景为 不愿为子类特意创建一个构造函数,于是以现有的对象作为原型浅拷贝得到子类实例(似乎看不出明确父子关系 但是不失为一种继承)
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
// 出发点就是不愿意建子类的构造函数,因此也没有把constructor指回去
缺点就是这种浅拷贝 多个实例都可以去修改父类的引用类型属性(可他们以为改的是自己的属性)因此父类的引用属性会被共享