一。在js中,继承的主要思路就是利用原型链,因此如果理解了原型链,继承问题就理解了一半。
原型链的原理是:让一个引用类型继承另一个引用类型的属性和方法。
-
原型对象通过
constructor
属性指向构造函数 -
实例通过
[Prototype]
属性指向原型对象
继承首先需要一个父类:
function Father(name){ // 属性 this.name = name || 'father', // 实例方法 this.sleep = function(){ console.log(this.name+"正在睡觉"); } } // 原型方法 Father.prototype.look = function(book){ console.log(this.name + "正在看:" + book); }
1.原型继承
核心:将父类的实例作为子类的原型(并不是把父类中的属性和方法克隆一份一模一样的给子类,而是让子类父类之间增加了原型链接)
特点:父类中私有的和公有的都继承到了子类原型上(子类公有的)
function Son(){ } Son.prototype = new Father() // 相当于重写了Son的原型 Son.prototype.constructor = Son; // 一定要把Son原型上的contructor重新指向Son var son = new Son() console.log(son.sleep()) // father正在睡觉 console.log(son.look('TV')) // father正在看TV
2.call继承(构造继承)
核心:使用父类的构造函数来增强子类实例
特点:把父类私有的属性和方法,克隆一份一样的给子类私有的属性,Father执行的时候,把Father的中的this换成Son的实例,由于并不是new Father,所以Father.prototype上的属性无关
function Son(name){ Father.call(this) this.name = name } var son = new Son('son') console.log(son.sleep()) //son正在睡觉 console.log(son.look('TV')) // son正在看TV
3.冒充对象继承
核心:使用父类的构造函数来增强子类实例
特点:把父类私有的和公有的克隆一份一样的给子类
function Son(){ var temp = new Father() for(var k in temp){ this[k] = temp[k] } temp = null } var son = new Son() console.log(son.sleep()) // father正在睡觉 console.log(son.look('TV')) // father正在看TV
4.混合模式继承: 原型继承+call继承
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
特点:把父类私有的和公有的都变成了子类共有的,但是调用了两次父类构造函数,生成了两份实例
function Son(){ Father.call(this) } Son.prototype = new Fahter(); Son.prototype.constructor = Son; var son = new Son() console.log(son.sleep()) // father正在睡觉 console.log(son.look('TV')) // father正在看TV
5.寄生组合式继承
核心:通过寄生方式,去掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Son(){ Father.call(this) } Son.prototype = createObject(Father.prototype) Son.prototype.constructor = Son; function createObject(o){ function fn(){} fn.prototype = o; return new fn; }
组合继承
特点:既是子类的实例,也是父类的实例
可传参
函数可复用