深入理解继承的实现方式不仅仅有利于自己去造轮子,封装插件,更有利于我们去阅读一些框架的源码,
以下记录几种常见的继承方式
1. 原型链实现继承
function Father(){ this.name = "爸爸" } Father.prototype.sayName = function(){ console.log(this.name) } function Son(){ this.age = 18 //this.name = "儿子" 自己有就不会沿着原型链去找 } //子类原型对象指向父类实例实现继承 Son.prototype = new Father() //子类添加自己的原型方法 只能写在实例后面,不然会覆盖 Son.prototype.sayAge = function(){ console.log(this.age) } var s1 = new Son() s1.sayName() s1.sayAge() console.log(s1.name)
2. 构造函数实现继承
function Father(){ this.colors = ["red","yellow"] this.sayColor = function(){ console.log(this.colors) } } function Son(){ this.age = 18 Father.call(this) } var s1 = new Son() s1.colors.push("blue") s1.sayColor() var s2 = new Son() s2.sayColor() //构造函数实现继承由于属性是在构造函数中,而不是原型中,说明这种方法没办法实现共享方法
3.组合继承
function Father(name){ this.name = name this.colors = ["red","yellow"] } Father.prototype.sayName = function(){ console.log(this.name) } function Son(name,age){ this.age = age Father.call(this,name) } Son.prototype = new Father() Son.prototype.constructor = Son //子类原型指向子类构造函数 Son.prototype.sayAge = function(){ console.log(this.age) } var s1 = new Son("儿子",18) s1.colors.push("blue") console.log(s1.name) console.log(s1.colors) s1.sayName() s1.sayAge() //实例共享的属性方法借用原型链实现,实例私有的属性方法借用构造函数实现
4. 冒充对象实现继承
function Father(){ this.name = "爸爸" this.sayName = function(){ console.log(this.name) } } function Son(){ this.temp = Father this.temp() //执行这个方法,内部this指向实例化的对象,实现继承 delete this.temp //内部已实现继承,销毁这个属性 } var s1 = new Son() s1.sayName() console.log(s1)
5. 原型式继承
function object(o){ function F(){} F.prototype = o return new F() } var person = { name: "张强", sayName: function(){ console.log(this.name) } } var p1= object(person) console.log(p1.name) p1.sayName() //原型式继承所有属性方法全部在原型下,所有属性方法全部共享
6. 寄生式的继承
function createAnother(o){ var obj = object(o) obj.sayHi = function(){ console.log("hi hi~") } return obj } var p2 = createAnother(person) console.log(p2.name) p2.sayHi() //寄生式继承在原型式继承的基础上为新对象添加自己的属性方法
7. 寄生组合式继承
function inheritPrototype(subType,superType){ //利用中间变量实现子类的原型继承父类原型,而非父类的全部 var prototype = object(superType) prototype.constructor = subType subType.prototype = prototype } function Father(name){ this.name = name this.colors = ["red","yellow"] } Father.prototype.sayName = function(){ console.log(this.name) } function Son(name,age){ this.age = age Father.call(this,name) } inheritPrototype(Son,Father) Son.prototype.sayAge = function(){ console.log(this.age) } var s1 = new Son("二儿子",16) s1.sayAge() console.log(s1) //寄生组合式的继承能使 子类原型继承父类原型,子类构造函数继承父类构造函数的属性方法
那么问题来了,为什么不可以 Son.prototype = Father.prototype 来实现子类原型继承父类原型,好吧,我们来试试~
function Father(name){ this.name = name this.colors = ["red","yellow"] } Father.prototype.sayName = function(){ console.log(this.name) } function Son(name,age){ this.age = age Father.call(this,name) } Son.prototype = Father.prototype Son.prototype.constructor = Son Son.prototype.sayAge = function(){ console.log(this.age) } var s1 = new Son("张强",27) console.log(s1) s1.sayName() var f1 = new Father("冯博志") console.log(f1)
咋一看好像可以实现继承,但是子类原型上的属性方法影响到父类的原型方法,这里就涉及到js的浅拷贝问题,当一个改变另一个随之改变,所以,这种方法是不可取的。
总结:
js实现继承的方法主要有这些,但主要的是组合方式和寄生组合方式,使用继承能使用父类的属性和方法,增加代码的可复用性。