聊聊js中的"继承"

260 阅读4分钟

前提你先完全理解了原型链以及new的作用,否则先补一补再来看。

继承

如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类“ 继承是类与类之间的关系,所以new 构造函数不是继承

继承的作用

子类具有父类的属性和方法

思考:es6之前,js没有类,也就没有继承,为什么说js有继承?

我认为这是个悖论,js真的没有继承,不管是es5还是es6。js的“继承”是通过原型模拟的,这当然是Brendan Eich设计的时候搞的,因为js当时是用于一些简单的操作,比如表单验证,如果设计类的话,对于这个语言来说太重了
因此,他就把new命令引入了Javascript,用来从原型对象生成一个实例对象。但是,Javascript没有"类",怎么来表示原型对象呢?

这时,他想到C++和Java使用new命令时,都会调用"类"的构造函数(constructor)。他就做了一个简化的设计,在Javascript语言中,new命令后面跟的不是类,而是构造函数。考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。这是一个很高效的方法,不黑js了,这可还行。

类的定义

是创建对象的蓝图,描述了所创建的对象共同的属性和方法。通俗一点,能产生对象的叫做类 类提供了可重复使用性的好处。自行车制造商一遍一遍地重用相同的蓝图来制造大量的自行车。软件程序员用相同的类,即相同的代码一遍一遍地创建对象。

思考:那我们是否可以认为构造函数是类呢? 不是

你完全可以在运行时修改“类”。也就不存在专门作为“对象的模板”的“类”了
即使勉强把某些“确实用作构造函数的对象”当成所谓“类”,也无法回避:与 prototype 相比,它根本就不象是“对象的模板”啊。而 prototype ,它是直接用来复制的,顶天了是个“基本的对象”,也不是“类”。

js中的“继承”

所以,你应该懂了,js中的"继承"本质上是通过new 一个构造函数加上原型链模拟的,那么我们如何写出这么一个“继承”?

ES5

 function 熊(name){
     this.name = name                                           //熊的自身属性
 }
 熊.prototype.say = function(){
     console.log("我叫"+this.name+",我tm熊的力量")               //熊的自身方法
     return undefined
 }
 function 北极熊(name){
     熊.call(this, name)                                       //北极熊调用熊(构造函数)使北极熊的实例具有熊的自身属性
     this.color = 'white'                                     //北极熊的私有属性
 }
 
 北极熊.prototype.color = function(){
     console.log('我是白色的熊')
 }
 
var fn = function(){}   //为什么要写3行,直接北极熊.prototype=new熊()不就好了吗?由于new的副作用,会call熊()这个构造函数,让实例的北极熊的那一层属性出现name,所以我们用一个空函数,让空函数的原型=熊的原型,这个空函数相当于没有公共属性的熊。
fn.prototype = 熊.prototype                                 
北极熊.prototype = new fn()                                     //相当于让北极熊的原型链上熊的原型
-----------------------------------                              //上面3行等于下面一行,由于IE不支持下面这种写法,所以我们使用上面这样,主要用到了new的作用
北极熊.prototype.__proto__=熊.prototype



然后直接使用就好了var xiongDa=new 北极熊('熊大')

ES6

 class 熊{
     constructor(name){                                     //熊的自身属性,constructor(构造)
         this.name = name
     }
     say(){
          console.log("我叫"+this.name+",我tm熊的力量")      //原型链上的直接写在class上
         return undefined
     }
 }
 class 北极熊 extends 熊{                                   //extends北极熊的原型链上熊的原型。
     constructor(name){
         super(name)                                      //super 超类= 熊.call(this, name) ,就是执行你继承的类的constructor
         this.color = 'white'  
     }
     color(){
          console.log('我是白色的熊')                        //北极熊原型链上的方法
     }
 }

所以呢,前端一定要理解es5的写法,了解js的这样设计的目的,es6的类(class)不不是真正意义上的类,只是一个语法糖,本质上还是通过prototype模拟类,所以 js没有中,没有真正类,也就没有真正意义上的继承,希望以后大家以后说js的“继承”给它加上两个引号!