1.原型链继承
// 核心:将父类的实例作为子类的原型 // 核心代码 // SubType.prototype = new SuperType() // // 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。 // SubType.prototype.constructor = SubType; function Father(){ this.a = 100 } Father.prototype.fn = function(){ console.log(123); } function Son(){ this.b = 200 } Son.prototype = new Father() Son.prototype.fn1 = function(){ console.log(222); } // 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。 Son.prototype.constructor = Son var obj = new Son() console.log(obj); // 缺点: // 1. 子类型在实例化时不能给父类型的构造函数传参
2.借用构造函数继承
// 核心:将父类构造函数的内容复制给了子类的构造函数。这是所有继承中唯一一个不涉及到prototype的继承。 // SuperType.call(SubType); // 把Father当成是普通函数来使用 function Father(a){ this.a = a; //方法不能复用 this.fn = function(){ console.log(123); } } // Father.prototype.fn = function(){ // console.log(123); // } function Son(a){ Father.call(this,a)// this是obj实例 } var obj = new Son(100) console.log(obj); // 优点 借用构造函数的一个优点就是可以在子类构造函数中向父类构造函数传参 // 缺点:父类的方法不能复用,子类实例的方法每次都是单独创建的。
3.组合继承
// 组合继承 = 原型链继承 + 借用构造函数继承 // 原型链继承:实例的引用类型共享 // 借用构造函数继承:实例的引用类型不共享 function Father(a){ this.a = a } Father.prototype.fn = function(){ console.log(123); } function Son(a){ Father.call(this,a)//第二次调用Father this.b = 200 } Son.prototype = new Father()//第一次调用Father Son.prototype.fn1 = function(){ console.log(222); } Son.prototype.constructor = Son var obj = new Son(100) console.log(obj); // 基本的思路是使用原型链继承原型上的属性和方法,而通过借用构造函数继承实例属性 // 组合继承弥补了原型链和借用构造函数的不足,是 JavaScript 中使用最多的继承模式 // 优点: // 1. 父类的方法可以被复用 // 2. 子类构建实例时可以向父类传递参数 // 问题:父构造函数使用了两次 // 属性可能就有二个,一个是实例的,一个是原型上的
4.原型式继承
// 优点:父类方法可以复用 var father = { a:1, b:2, fn(){ console.log(111); } } var son1 = Object.create(father) console.log(son1); son1.fn() // 缺点: // 1. 子类构建实例时不能向父类传递参数
5.寄生式继承
// 使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力。 // 寄生式继承就是把原型式继承再次封装,然后在对象上扩展新的方法,再把新对象返回 // 没什么用 // 增强版原型式继承 var father = { a:1, b:2, fn(){ console.log(111); } } function factory(o,num){ var obj = Object.create(o) obj.a = num obj.fn1 = function(){ console.log(123); } return obj } var son1 = factory(father,100) console.log(son1); son1.fn()
6.寄生式组合继承
// 组合继承其实也存在效率问题。最主要的效率问题就是父类构造函数始终会被调用两次:一次在是 // 创建子类原型时调用,另一次是在子类构造函数中调用。本质上,子类原型最终是要包含超类对象的所 // 有实例属性,子类构造函数只要在执行时重写自己的原型就行了 function fn(Son,Father){ var subProto = Object.create(Father.prototype)// 创建了父类原型的浅复制 subProto.constructor = Sub // 修正原型的构造函数 Sub.prototype = subProto// 将子类的原型替换为这个原型 } function Super(name){ this.name = name } Super.prototype.sayHi = function(){ console.log(this.name); } function Sub(name){ Super.call(this,name)//属性可以传参 借用构造函数的方式 } // 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费 fn(Sub,Super) Sub.prototype.sayHello = function(){ console.log('sayHello'); } var o = new Sub('zs') console.log(o);
7.class类式继承
class Son extends Father{ }