JavaScript常用的几种继承方式

时间:2022-09-08 14:58:15

JavaScript是面向对象的弱类型语言,继承是其重要的特性之一,这里总结下常用的四种继承方法。

先定义一个父级构造函数,并在其原型上添加一个speak方法

//定义父级构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.intro = function() {
        console.log(this.name + ' is ' + this.age + ' years old');
    }
}
//父级原型添加新方法
Person.prototype.speak = function(language) {
    console.log(this.name + ' can speak ' + language);
}

以下四种继承方式均在此父级构造函数基础上实现。

1、传统形式,通过原型链继承

将父级构造函数的实例作为子级构造函数的原型

//定义子级构造函数
function Man() {

}
//将父级实例作为子级原型
Man.prototype = new Person('Jack', 18);
//子级原型添加name属性会覆盖原型name属性
Man.prototype.name = 'Toms';
//创建子级实例对象
var man = new Man();
//调用父级构造函数内的方法
man.intro(); // Toms is 18 years old
//调用父级原型自定义的speak方法
man.speak('Chinese'); // Toms can speak Chinese

缺点:继承父级所有属性和方法,没有选择性

2、通过父级构造函数,即子级构造函数内调用父级构造函数

其实就是借用别人的方法,实现自己的功能

function Man() {
    Person.call(this);
    this.name = 'Jack';
    this.age = 19
}
var man = new Man();
// 借用Person的intro方法 man.intro();
// Jack is 19 years old

 缺点:不能继承父级构造函数原型,每次创建实例要多运行一个构造函数

3、通过原型共享实现继承

即子级原型等于父级原型

 

function Man(name) {
    this.name = name;
}
//构造函数原型共享
Man.prototype = Person.prototype;
var man = new Man('Jack');
//子级实例可调用共享的原型上的方法speak
man.speak('Chinese'); // Jack can speak Chinese

缺点:共享原型,一个修改原型属性和方法,另一个会同步

4、堪称完美的圣杯模式

通过在一个立即执行函数中定义一个临时构造函数,来中转源构造函数到目标构造函数的原型链,这样修改目标构造函数的原型不会直接影响到源构造函数原型,

同时执行完毕立即销毁,减少内存开销。

var inherit = (function () {
    var Temp = function () {}; // 定义临时构造函数用于原型链的中转
    return function (Target, Origin) {
        Temp.prototype = Origin.prototype; // Temp继承Origin原型
        Target.prototype = new Temp(); // Target继承Temp对象原型
        Target.prototype.constructor = Target; // 改写Target原型上的构造器指向
        Target.prototype.ancestor = Origin.prototype; // 标记Target真正继承的原型
    }
}());