基本概念:
- prototype:显性原型,获取共享的属性和方法
- __proto__( [[Prototype]] ):隐式原型,指向构造函数的原型,如:function a(){}; var b = new a(); b.__proto__ == a.prototype
- constructor:指向的是构造函数,如:var a = new Array(); a.construtor === Array
prototype只有函数有
__proto__是对象就有,不过不推荐使用(比较耗性能),推荐使用Object.getPrototypeOf(obj)
Object.prototype.__proto__ = null,可以理解Object就是原型链最高级
Function.__proto__.__proto__ == Object.prototype,可以理解Function继承自Object
1、原型链方式
function AA(name) { this.name = name }
AA.prototype.sex = 'man'
function BB() { }
BB.prototype = new AA()
BB.prototype.cunstructor = BB
BB.prototype.sex === 'man'
缺点
- 子类创建实例时无法给父类构造函数传参
- 父类中如果有引用类型的属性时,所有子类都可操作该属性,例子
2、构造函数方式
function AA(name) { this.name = name }
AA.prototype.sex = 'man'
function BB(name) {
AA.call(this, name)
}
BB.prototype.sex === undefined
缺点
- 这种方式虽然能给父类构造函数传参,但是无法获取父类的原型属性
3、原型链加构造函数组合方式继承
function AA(name) { this.name = name }
AA.prototype.sex = "man"
function BB() { AA.call(this, "BB") } // 调用AA,实例化后也可以用name
// 方式一,推荐
// 继承,BB.prototype.__proto__ == AA.prototype
BB.prototype = Object.create(AA.prototype)
// 方式二
// 将父类的实例对象做原型,可以将AA的实例属性赋给BB并将__proto__指向AA的原型
// BB.prototype = new AA()
BB.prototype.cunstructor = BB // 需要重新指定construct,否则指向AA
BB.prototype.sex == "man"
缺点
- 这种方式解决了大部分缺点,但还是有引用类型属性共享的问题,不过只涉及原型上的引用类型属性(通过this操作也会有影响)
4、圣杯模式
function AA (name) { this.name = name }
AA.prototype.sex = 'man'
function BB () {}
/** function _extends (b, a) {
function _() {}
_.prototype = a.prototype
b.prototype = new _()
b.prototype.constructor = b
} */
function _extends = (function () {
function _() {}
return function (b, a) {
_.prototype = a.prototype
b.prototype = new _()
b.prototype.constructor = b
}
})()
_extends(BB, AA)
- 这种方式和原型链方式的区别就是不会把父类的私有属性赋给子类的原型
5、setPrototypeOf
function AA () {}
AA.prototype.age = 0
function BB () {}
// 将BB.prototype.__proto__指向AA.prototype
Object.setPrototypeOf(BB.prototype, AA.prorotype)
BB.prototype.constructor = BB
BB.prototype.age === 0
6、class/extends
继承的实现就是将父类原型添加到原型链上
多个继承:
若有多个继承可用Object.assign(target,...sources),会将所有sources的对象复制到target目标对象,注意:重复的属性会被覆盖
继承使用:Object.assign(BB.prototype, AA.prototype)