深入理解继承的实现方式不仅仅有利于自己去造轮子, 封装插件, 更有利于我们去阅读一些框架的源码,
以下记录几种常见的继承方式
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 实现继承的方法主要有这些, 但主要的是组合方式和寄生组合方式, 使用继承能使用父类的属性和方法, 增加代码的可复用性.
来源: https://www.cnblogs.com/zhuzeliang/p/9140343.html