js实现继承的方法
ps:此文仅作笔记
1、原型链继承
2、构造函数继承
3、组合继承
4、原型式继承
5、寄生式继承
6、寄生组合式继承
1. 原型链继承
function Parent () {
this.name = 'parent';
}
Parent.prototype.getName = function () {
return this.name
}
function Child () {
}
// 将子的prototype指向父亲的实例,这样就具有name属性和getName方法
Child.prototype = new Parent();
var child1 = new Child();
console.log(child1.getName(),child1.name) // parent,parent
缺点:
- 因为所有的子例的
__proto__
都指向 同一个 new Parent(),所以会存在引用修改的问题 - 无法传递参数
2. 构造函数继承
使用parent.call来实现将parent的属性绑定到子函数中
function Parent (name) {
this.name = name;
}
Parent.prototype.getName = function () {
return this.name
}
function Child (name) {
Parent.call(this,name) // 只能继承父类的属性,不能继承方法
}
var child1 = new Child('child');
console.log(child1.name) // child
console.log(child1.getName()) // Error
缺点:
- 无法继承父类原型的方法,若getName改成Parent属性,则子类的实例就有getName方法:
function Parent (name) {
this.name = name;
this.getName = function () {
return this.name
}
}
console.log(child1.getName()) // child
3、组合继承
function Parent (name) {
this.name = name;
this.house = ['house1','house2']
}
Parent.prototype.getName = function () {
return this.name
}
function Child (name) {
Parent.call(this,name) // 构造函数继承,第一次调用parent
}
Child.prototype = new Parent() // 原型链继承 // 第二次调用parent
Child.prototype.constructor = Child; // 恢复子类的构造函数
var child1 = new Child('child1');
var child2 = new Child('child2')
child1.house.push('house3')
console.log(child1.name) //child1
console.log(child1.getName()) //child1
console.log(child1.house); //[ 'house1', 'house2', 'house3' ]
console.log(child2.house); //[ 'house1', 'house2' ]
console.log(child1 instanceof Child,child1 instanceof Parent); // true,true
缺点:会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部
4、原型式继承
// 借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
1、自定义一个函数来实现原型式继承
function object(o){
function F(){}
F.prototype = o;
return new F();
}
parent = {a:{a:1}}
child = object(parent)
child.a = 1
console.log(child.a); // 1
console.log(parent.a); // {a:1}
也可以使用 Object.create(obj1,obj2)实现obj1继承obj2的属性
5、寄生式继承
使用Object.create来新建一个对象,然后将新的方法添加(寄生)到该对象中,
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () { // 寄生
console.log('hi');
}
return clone;
}
缺点:做不到函数复用,因为若有新的方法,得重写createObj的寄生过程
6. 寄生组合式继承
function Parent (name) {
this.name = name;
this.house = ['house1','house2']
}
Parent.prototype.getName = function () {
return this.name
}
function Child (name) {
Parent.call(this,name) // 构造函数继承,只有这里调用了父类的构造函数
}
Child.prototype = Object.create(Parent.prototype) // 赋值prototype是原型链继承,Object.create是寄生式继承的一部分
Child.prototype.constructor = Child;
Child.prototype.SayHello = function(){ // 寄生新方法
console.log("hello,I’m",this.name);
}
var child1 = new Child('child1');
var child2 = new Child('child2')
child1.house.push('house3')
child1.SayHello() //hello,I’m child1
console.log(child1.name) //child1
console.log(child1.getName()) //child1
console.log(child1.house); //[ 'house1', 'house2', 'house3' ]
console.log(child2.house); //[ 'house1', 'house2' ]
console.log(child1 instanceof Child,child1 instanceof Parent);
只调用一次 Child构造函数,并且因此避免了在 Child.prototype 上面创建不必要,多余的属性。与此同时,原型链还能保持不变;因此还能够正常使用 instance 操作符和 isPrototype() 方法
理论上,以上方法都可以使用instanceof方法,可以等我把isInstance的原理总结一下再看看