原型链
首先你要弄懂什么是js的原型链机制,执行下面两行代码后,相关的原型链大概就如图所示。
let Foo = function(){}
let f1 = new Foo()
Object.create和new
这两个在具体实现中都实现了很重要的一些步骤。
-
Object.create 是创建一个新对象,使用现有的对象来提供新创建对象的 proto。意思就是生成一个新对象,该新对象的 proto(原型) 指向现有对象。
-
new 生成的是构造函数的一个实例,实例继承了构造函数及其 prototype(原型属性)上的属性和方法。
new关键字创建的对象会保留原构造函数的属性,而用Object.create()创建的对象不会。
来看如下代码。
两者不同在于,Object.create 创建的新函数并没有继承构造函数的属性和方法,只继承了原型方法和原型属性
这就是为什么组合寄生式继承优于普通的组合继承的地方,因为之前已经继承过一次,不再重复继承多一次原型的属性和方法。
寄生组合继承的实现
首先,请看下面的一种实现继承的方式,直接在子类中调用父类.call()。
这种继承会导致的问题是,子类的原型链并不指向父类,即子类 instanof 父类 为false,这显然是不合适的。
所以在考虑初始化继承一次后,还要在外部继承一次。这样就是普通的组合继承方式,这种方式会创建两份父类实例,因此显得臃肿。
对普通的组合继承改进,要引入一个空类,这个空类的{{proto}}指向父类,这样外部继承只要继承在这个寄生在父类上的空类就好了。这便是继承组合继承机制。
来看如下代码。
function SuperType(name) {
this.name = name;
this.colors = ["red","green","black"];
};
SuperType.prototype.sayName = function() {
return this.name
};
function SubType(name, age) {
SuperType.call(this, name); //继承一次
this.age = age;
};
let superType01 = new SuperType("卢本伟")
let subType01 = new SubType("卢本伟", 18)
现在实现组合寄生式继承,看看又会是怎么样的改变?
function SuperType(name) {
this.name = name;
this.colors = ["red","green","black"];
};
SuperType.prototype.sayName = function() {
return this.name
};
function SubType(name, age) {
SuperType.call(this, name); //继承一次
this.age = age;
};
// let superType01 = new SuperType("卢本伟")
// let subType01 = new SubType("卢本伟", 18)
/* 普通组合继承 */
// SubType.prototype = new SuperType(); //继承第二次
/* 组合寄生 */
function inherit(son,father){
// 步骤一
let tmpObj = Object.create(father.prototype) //不发生第二次继承
console.log(tmpObj)
// 步骤二
tmpObj.constructor = son
// 步骤三
son.prototype = tmpObj
}
inherit(SubType,SuperType)
SubType.prototype.sayAge = function () {return this.age};
let superType02 = new SuperType("伞兵一号")
let subType02 = new SubType("伞兵一号", 18)
原理图如下,我画了好一会的作品呢,足够一目了然了吧!
最终运行结果。
让你豁然开朗的原理图
单独拿出来,以后一看到这张图,有关js的继承问题,一切都豁然开朗了。