创建 js 样例:
1 | /* |
这样创建比较合理
原型链继承
这是实现继承最简单的方式,核心就是一句话
实例
1 | function Super() { |
核心
拿父类实例充当子类原型对象优缺点
优点:
简单,易于实现
缺点:
修改 sub1.arr 后 sub2.arr 也变了,因为来自原型对象的引用树形是所有实例共享的。
执行顺序:执行 sub1.arr.push(2);先对 sub1 进行属性查找,找遍了实例属性(在本例中没有实例属性),没找到,就开始顺着原型链向上找,拿到了 sub1 的原型对象,一搜身,发现有 arr 属性。于是给 arr 末尾插入了 2,所以 sub2.arr 也变了
创建子类实例时,无法向父类构造函数传参
借用构造函数
简单原型链真够简单,可是存在 2 个致命缺点简直不能用,于是上个世纪末的 jsers 就想办法 fix 这 2 个缺陷,然后出现了借用构造函数方式
实例
1 | function Super(val) { |
核心
借父类的构造函数来增强子类实例,等于是把父类的实例属性复制了一份给子类实例装上了(完全没有用到原型)
优缺点
优点
解决了子类实例共享父类引用属性的问题
创建子类实例时,可以向父类构造函数传参
缺点
无法实现函数复用,每个子类实例都持有一个新的 fun 函数,太多了就会影响性能
组合继承(常用)
目前我们的借用构造函数方式还是有问题(无法实现函数复用),没关系,接着修复,jsers 吭哧吭哧又搞出了组合继承
实例
1 | function Super() { |
核心
<font color=”red>把实例函数都放在原型对象上,以实现函数复用。同时还要保留借用构造函数方式的优点,通过 Super.call(this);继承父类的基本属性和引用属性并保留能传参的优点;通过 Sub.prototype = new Super();继承父类函数,实现函数复用
优缺点
优点
不存在引用属性共享问题
可传参
函数可复用
缺点
子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的
寄生组合继承(最佳方式)
从名字就能看出又是对组合继承的优化
实例
1 | function beget(obj) { |
construcotr 可参考:
核心
用 beget(Super.prototype);<font color=”red>切掉了原型对象上多余的那份父类实例属性
寄生组合式继承,这名字不是很贴切,和寄生式继承关系并不是特别大
原型式
其实介绍完上面的完美方案就可以结束了,但从组合继承到完美方案好像有一段不小的思维跳跃,有必要把故事说清楚
实例
1 | function beget(obj) { |