JavaScript 继承相关概念究级备忘录

fecoding 2019-03-29

1. 基础

function Parent (name) {
    this.name = name;
}

var son = new Parent('chris');


// 实例的 contructor 指向实例的构造函数
console.log(son.constructor === Parent); // true

// instanceof 用于验证实例与原型对象的关系
console.log(son instanceof Parent);      // true

// isPrototypeOf 用于验证实例与 prototype 对象的关系
console.log(Parent.prototype.isPrototypeOf(son))  // true

// 实例的 __proto__ 指向其构造函数的 prototype 对象
console.log(son.__ptoto__ === Parent.prototype);  // true

// __proto__ 是每个对象都有的属性,prototype 属性只有函数才有

2. 构造函数继承

假设有如下两个类

function Person () {
    this.type = 'human';
}

function Parent (name) {
    this.name = name;
}

想要实现 Parent 继承 Person,常见的有以下四种方式:

/* 1. 构造函数绑定 */

function Parent (name){
    Person.apply(this, arguments);
    this.name = name;
}

/* 2. prototype 模式 */
Parent.prototype = new Person();

// prototype 对象的 contructor 属性应该指向构造函数,
// 上一步使得 Parent.prototype.contructor === Person
// 此后将使 son.prototype === Parent.prototype === Person,造成继承链紊乱,因此需要修正
Parent.prototype.contructor = Parent;

/* 3. 直接继承 prototype */

// 优点:效率高,不用创建实例,节省内存
// 缺点:任何对 Parent.prototype 的修改将直接影响 Person.prototype
// 缺点:Person.prototype.contructor 也被修改(=== Parent)

Parent.prototype = Person.prototype;
Parent.prototype.contructor = Parent;

/* 4. 利用空对象作为中介 */

var F = function () {};

F.prototype = Person.prototype;
Parent.prototype = new F();
Parent.prototype.constructor = Parent;

3. 非构造函数继承

假设有以下两个对象

var father = {
    lastname: 'paul'
};

var son = {
    height: 180
};

需要实现 son 对 father 的继承,有以下几种方式:

/* 1. 空函数作中介 */
function object (o) {
    var F = function () {};
    F.prototype = o;
    
    return new F();
}

var son = object(father);
son.height = 180;


/* 2. 浅拷贝、深拷贝*/
// 逐个将父对象的属性拷贝至子对象

4. End

最后,送上知乎用户 @doris 的一图流作为结尾:
JavaScript 继承相关概念究级备忘录

相关推荐