全回顾扫盲js之继承方法梳理

call/apply方法

首先,call和apply都继承自Function

console.log(Function.apply, Function.call)  // function apply() { [native code] } function call() { [native code] }

优点:方便快捷,可以直接继承。缺点:并不能继承上一级的原型对象,只是改变了构造函数中this的指向。

function parent1 () {
  this.name = 'name'
}
parent1.prototype.sex = function () {
    return 'man'
}
function child1 () {
    parent1.call(this)
  this.age='23'
}

console.log(new child1())
console.log(new child1().name)
console.log(new child1().__proto__)
console.log(new child1().__proto__.sex())

原型对象指向构造函数

优点:可以继承到父级的原型对象。缺点:1.构造函数会被多次执行。2.原型对象的constructor指向会被改变,并不指向本身的构造函数。3.会改变构造函数。

  function Parent2 () {
    this.name = 'parent2'
    this.list = [1,2,3]
  }
  Parent2.prototype.sex = function () {
    return 'man'
  }
  function Child2 () {
    this.age = '27'
  }
  Child2.prototype = new Parent2()

  var C1 = new Child2()
  var C2 = new Child2()

  console.log(C1.__proto__.sex())   // 继承了prototype对象
  console.log(C1.__proto__.constructor) // function Parent2() {}
  console.log(C1.list)  // [1, 2, 3]
  C2.list.push(4)
  console.log(C1.list)      // [1, 2, 3, 4]

构造函数被多次执行我们也就忍了,但新生对象居然会反过来改变构造函数,这怎么能忍得了。接下来我们利用混合方法优化一下。

首先我们可以利用call方法来继承构造函数的属性,然后用prototype直接指向父级的prototype属性,这样避免了构造函数多次被调用影响性能的问题。

function Parent3 () {
   this.name='小明'
   this.list = [1,2,3]
}
function Child3 () {
   Parent3.call(this)
   this.age = '27'
}
Child3.prototype = Parent3.prototype
var C1 = new Child3()
var C2 = new Child3()

console.log(C1.list)    // [1, 2, 3]
C2.list.push(4)
console.log(C1.list)    // [1, 2, 3]

这时,还有一个原型对象指向的问题需要解决。但是Child3的原型对象是指向Parent3的原型对象,根据对象的引用关系,如果直接改了Child3.prototype的constroctor属性,Parent3.prototype的指向同样会被改变

我们用Object.Create来解决这个问题

function Parent4 () {
  this.name = '小名'
  this.list = [1,2,3]
}
function Child4 () {
  Parent4.call(this)
  this.age = '27'
}
Child4.prototype = Object.create(Parent4.prototype)
Child4.prototype.constructor = Child4

var C1 = new Child4()
console.log(C1.__proto__.constructor)   // function Child4() {}

随机浏览