Js里的继承一般就是原型链继承。即实现A的原型的原型为B的原型,则A继承B。
首先需要了解下实例,构造函数,原型对象之间是怎样的关系。实例为从构造函数new得到的新对象,它有__proto__可以指向原型对象,通过instanceof方法可以判断实例的构造函数类型;构造函数的prototype指向原型对象,原型对象有constructor指向构造函数。详细了解可以参考https://segmentfault.com/a/1190000008959943

了解了三者关系之后,我们需要做的其实就是更改A的原型。让新的原型满足两个条件:

  1. 新原型的原型指向被继承者B
  2. 新原型的构造函数指向A
function A() {
}
function B() {
}
B.prototype.say = function(){console.log('say')}

// 准备一个中间变量
function C(){}
// 重新设置C的原型为B的原型
C.prototype = B.prototype
// 创建一个实例c,此时c的原型是B的原型
var c = new C()
// 设置实例c的构造函数指向A,
c.constructor = A

// 上述步骤后A新的原型对象c创建完成,它的原型指向B,构造函数指向A
A.prototype = c
// 此时原型链为 new A()._proto__ (c) => B.prototype => Object.prototype => null
console.log(new A(), new B())

image.png

有的人可能会奇怪,为什么不能直接使用A.prototype = B.prototype,这样的话相当于A,B共用一个原型对象,A在原型的更改会直接影响B,不符合继承要求,子类无法独自扩展;而且,A的原型对象的构造函数此时指向的是B,意味着实例无法重新访问构造函数。

function A() {
}
function B() {
}
B.prototype.say = function(){console.log('say')}
A.prototype = B.prototype
A.prototype.sayA = function(){console.log('sayA')}
console.log(new B().sayA()) // sayA
console.log(new A().__proto__.constructor) // function B() {}

常见的介绍js继承的文章有很多,里面一般介绍了诸如原型继承,构造函数继承,组合继承等等,以及不同方式的缺点与优点,看的懵懵的,但我们只要知道这些方式的本质就是创建原型链(A的原型的原型为B的原型),那些方法其实就很好理解了。要做到继承直接使用A.prototype.__proto__ = B.prototype 或者Object.setPrototypeOf(A.prototype, B.prototype)也完全可以,但是要注意是否支持。详细了解参考MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf


feng
9 声望0 粉丝