Javascript 继承实现一览

198 阅读2分钟

面向对象

前言:面向对象是一种编程思想,基于这种思想,大大提高了代码的复用率。而在js中,用于es6之前并没有类的概念,而是提供了一个构造函数的概念,将原型prototype作为类的实现方法,导致js提出了众多的继承思想,以下列举一些典型的方法。

继承

1. 原型链继承

核心方法:将父类的实例作为子类的原型。

特点:

  • 关系明确,实例不仅是子类的实例,也是父类的实例。
  • 父类所有的以及添加的原型方法/原型属性,子类都可以访问到。
  • 实现简单。

缺点:

  • 来自原型对象的所有属性被所有实例共享。
  • 无法实现多继承。(多继承指一个类可以继承多各类,如:A可以同时继承B类和C类)
// 推荐程度 ★☆☆☆☆
// 父类
function Father(){
	this.lastName = 'Smith'
}
Father.prototype.getLastName = function(){
    return this.lastName
}
// 子类
function Son(){
	this.firstName = 'son'
}

Son.prototype = new Father()
Son.prototype.getFirstName = function(){
    return this.firstName
}

var son = new Son()
console.log(son.firstName)
console.log(son.lastName)
console.log(son.getFirstName())
console.log(son.getLastName())

2. 构造函数继承

核心:call()方法是构造函数继承的精华所在。

call方法改变了函数的作用环境,因此只能继承父类实例中的属性和方法,不能继承原型对象上的方法

特点:

  • 实例化子类时,可以向父类传递参数
  • 能够实现多继承(可以call多个父类)

缺点:

  • 不能继承原型属性及方法
// 推荐程度 ★★☆☆☆
// 父类
function Father(firstName){
    this.firstName = firstName
	this.lastName = 'Smith'
}
Father.prototype.getLastName = function(){
    return this.lastName
}
// 子类
function Son(firstName){
    Father.call(this,firstName)
}
var son = new Son('son')
console.log(son.firstName)
console.log(son.lastName)
console.log(son.getLastName()) // throw Error

3. 组合继承

这种继承即将原型继承以及构造函数继承结合起来,优点很明显,包含了两种继承方式的优点。

缺点也很明显,在子例构造函数继承时执行了一边父类的构造函数,原型继承时又调用了一遍父类的构造函数。重复调用

// 推荐程度 ★★★☆☆
// 父类
function Father(firstName){
    this.firstName = firstName
	this.lastName = 'Smith'
}
Father.prototype.getLastName = function(){
    return this.lastName
}
// 子类
function Son(firstName){
    Father.call(this,firstName)
}
Son.prototype = new Father()
var son = new Son('son')
console.log(son.firstName)
console.log(son.lastName)
console.log(son.getLastName())

4. 寄生组合式继承

核心:声明一个空的构造函数F,利用这个构造函数继承父类,子类再继承F的原型

// 继承方法 推荐程度 ★★★★☆
function inherit(Target,Origin){
   function F (){ }
   F.prototype = Origin.prototype
   Target.prototype = new F()
   Target.constructor = Target
}
// YUI3 闭包 推荐程度 ★★★★★
var inherit = (function(){
    var F = function(){ }
    return function(Target,Origin){
       F.prototype = Origin.prototype
       Target.prototype = new F()
       Target.constructor = Target
       Target.prototype.uber = Origin.prototype
    }
})()

总结:虽然继承方法很多,但还是推荐最后两个,YUI3中还利用了闭包