Open huihuiha opened 3 years ago
上面代码看似没问题,实际存在潜在问题
var s1 = new Child2(); 这句里的 Child2 在哪声明的 ?
ES5与ES6的继承区别
请问真的会有面试官问这种问题吗?
// 手动挂上构造器,指向自己的构造函数 Child3.prototype.constructor = Child3; 这两句是什么意思?
会有的,比如米哈游前端面试就是这类八股文大合集
感觉此系列题库有不少错误。
这里 JavaScript 拼错了
请问真的会有面试官问这种问题吗?
真问了。。。似乎从这里复制的面试题
一、是什么
继承(inheritance)是面向对象软件技术当中的一个概念。
如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”
继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码
在子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能
虽然
JavaScript
并不是真正的面向对象语言,但它天生的灵活性,使应用场景更加丰富关于继承,我们举个形象的例子:
定义一个类(Class)叫汽车,汽车的属性包括颜色、轮胎、品牌、速度、排气量等
由汽车这个类可以派生出“轿车”和“货车”两个类,在汽车的基础属性上,为轿车添加一个后备厢、给货车添加一个大货箱
这样轿车和货车就是不一样的,但是二者都属于汽车这个类,汽车、轿车继承了汽车的属性,而不需要再次在“轿车”中定义汽车已经有的属性
在“轿车”继承“汽车”的同时,也可以重新定义汽车的某些属性,并重写或覆盖某些属性和方法,使其获得与“汽车”这个父类不同的属性和方法
从这个例子中就能详细说明汽车、轿车以及卡车之间的继承关系
二、实现方式
下面给出
JavaScripy
常见的继承方式:原型链继承
构造函数继承(借助 call)
组合继承
原型式继承
寄生式继承
寄生组合式继承
原型链继承
原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例,三者之间存在着一定的关系,即每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指针
举个例子
上面代码看似没问题,实际存在潜在问题
改变
s1
的play
属性,会发现s2
也跟着发生变化了,这是因为两个实例使用的是同一个原型对象,内存空间是共享的构造函数继承
借助
call
调用Parent
函数可以看到,父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法
相比第一种原型链继承方式,父类的引用属性不会被共享,优化了第一种继承方式的弊端,但是只能继承父类的实例属性和方法,不能继承原型属性或者方法
组合继承
前面我们讲到两种继承方式,各有优缺点。组合继承则将前两种方式继承起来
这种方式看起来就没什么问题,方式一和方式二的问题都解决了,但是从上面代码我们也可以看到
Parent3
执行了两次,造成了多构造一次的性能开销原型式继承
这里主要借助
Object.create
方法实现普通对象的继承同样举个例子
这种继承方式的缺点也很明显,因为
Object.create
方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能寄生式继承
寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法
其优缺点也很明显,跟上面讲的原型式继承一样
寄生组合式继承
寄生组合式继承,借助解决普通对象的继承问题的
Object.create
方法,在亲全面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式可以看到 person6 打印出来的结果,属性都得到了继承,方法也没问题
文章一开头,我们是使用
ES6
中的extends
关键字直接实现JavaScript
的继承利用
babel
工具进行转换,我们会发现extends
实际采用的也是寄生组合继承方式,因此也证明了这种方式是较优的解决继承的方式三、总结
下面以一张图作为总结:
通过
Object.create
来划分不同的继承方式,最后的寄生式组合继承方式是通过组合继承改造之后的最优继承方式,而extends
的语法糖和寄生组合继承的方式基本类似相关链接