对象、原型、继承(二)

219 阅读2分钟

继承是面向对象语言(Object-Oriented Language)中的一个最为人津津乐道的概念。JS中的继承主要是依靠原型链 来实现的。

原型链

ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原 型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每 个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型 对象的内部指针(__proto__)。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的 原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数 的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实 例与原型的链条。这就是所谓原型链的基本概念。

ES5实现

结合前面的构造函数和原型的概念,我们先定义一个构造函数

function Animal(name){
  this.name = name
}
Animal.prototype.run = function(){
  console.log(this.name + ' is running')
}

再定义子类的构造函数:

function Dog(color, name){
  Animal.call(this, name)
  this.color = color
}
Dog.prototype.jump = function(){
  console.log(this.name + ' ' + this.color + ' is jumping')
}

这里需要注意的是,Animal.call(this, name)通过使用apply()/call()方法也可以在(将来)新创建的对象上执行构造函数。

然后我们需要将Dog.prototype的__proto__指向Animal.prototype,实现原型链的继承

var tmp = function(){}
tmp.prototype = Animal.prototype
Dog.prototype = new tmp()

这里使用一个函数作为“桥梁”,让它的原型对象指向Animal的原型对象,再用new操作符,将Dog 的原型对象的__proto__指向它的原型对象。为什么不直接new Animal呢?因为直接用的话要注意传入name形成实例,这里相当于只是复制了一份Animal.prototype。

事实上这三部可以用Dog.prototype = Object.create(Animal.prototype)来代替,本质上是一样的。MDN Object.create

Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constuctor = Dog

这里需要将Dog的原型对象的constructor指向其构造函数,也就是Dog。这样就完整的实现了一个JS继承。

最后是使用:

var ex = new Dog('red','来福')
console.dir(Animal)
console.dir(Dog)
console.log('ex: ')
console.dir(ex)

ei2Xxx.png

ES6实现

ES6实际上是JavaScript现有的基于原型的继承的语法糖。详细可以参考MDN extend

class person {
  constructor(name, age){
    this.name = name
    this.age = age
  }
  say(){
    console.log(`${this.name} saying`)
  }
}

const a = new person('kuma', 29)

a.say() //"kuma saying"

class man extends person {
  constructor(name, age, sex){
    super(name, age)
    this.sex = sex
  }
  run() {
    console.log(`${this.name} running ${this.sex}`)
  }
}

const b = new man('alex', 29, 'is man')
b.run() //"alex running is man"
b.say() //"alex saying"

相比较而言,ES6的写法更容易理解和使用,项目中如果为了兼容,使用babel转译即可。