Javascript原型链继承的理解

65 阅读1分钟

首先来个两个构造函数 Parent,Child

function Parent (a) {
    this.a = a
}

function Child (a, b) {
    this.a = a
    this.b = b
}

const child = new Child('aa', 'bb')
console.log(child) // {a: 'aa', b: 'bb'}

简单继承改造

function Parent (a) {
    this.a = a
}

function Child (a, b) {
    Parent.call(this, a)
    this.b = b
}

const child = new Child('aa', 'bb')
console.log(child) // {a: 'aa', b: 'bb'}

但是给父的原型上添加方法,执行child.fn()会报错,说明原型上的值或方法没有被继承

function Parent (a) {
    this.a = a
}

Parent.prototype.fn = function () {
    console.log('fn')
}

function Child (a, b) {
    Parent.call(this, a)
    this.b = b
}

const child = new Child('aa', 'bb')
console.log(child) // {a: 'aa', b: 'bb'}
child.fn() // Uncaught TypeError: child.fn is not a function

执行child.fn()的步骤:

  1. child自己身上找fn方法,发现没有,再去child.__proto__上找,没有找到会依次找 child.__proto__.__proto__child.__proto__.__proto__.__proto__...,这就是所谓的原型链;
  2. 我们再看child.__proto__是什么?其实child.__proto__ === Child.prototype
  3. Child.prototype这个上面也没有fnfn存在Parent.prototype上,这样就好办了,我让Child.prototype.__proto__ = Parent.prototype那就可以找到fn了;

所以加上这行代码Child.prototype.__proto__ = Parent.prototype

function Parent (a) {
    this.a = a
}

Parent.prototype.fn = function () {
    console.log('fn')
}

function Child (a, b) {
    Parent.call(this, a)
    this.b = b
}

Child.prototype.__proto__ = Parent.prototype

const child = new Child('aa', 'bb')
console.log(child) // {a: 'aa', b: 'bb'}
child.fn() // fn

这样就不报错了,可以找到fn执行了。

但是不推荐直接修改对象的__proto__属性,推荐用Object.setPrototypeOf()方法

改造代码

function Parent (a) {
    this.a = a
}

Parent.prototype.fn = function () {
    console.log('fn')
}

function Child (a, b) {
    Parent.call(this, a)
    this.b = b
}

// Child.prototype.__proto__ = Parent.prototype
Object.setPrototypeOf(Child.prototype, Parent.prototype)

const child = new Child('aa', 'bb')
console.log(child) // {a: 'aa', b: 'bb'}
child.fn() // fn