js-对象几种继承方式

注意:

  1. constructor总是指向类的构造函数
  2. __proto__指向父类的原型对象
  3. instanceof可以判断构造函数的继承关系

一、原型链继承

function Father(name) {
    this.name = name;
    this.color = ['red', 'blue'];
}
Father.prototype.getName = function () {
    console.log(this.name)
}
function Child() { }
Child.prototype = new Father();
Child.prototype.constructor = Child;
var son1 = new Child('ming');
var son2 = new Child('wei');
son1.color.push('white');
son2.color; //['red','blue','white']

缺点:对于复杂数据类型color,多个实例对引用的操作会被篡改

二、借用构造函数继承

function Father(name) {
    this.name = name;
}
Father.prototype.getName = function () {
    console.log(this.name)
}
function Son(name) {
    Father.apply(this, arguments);
}
var son = new Son('ming');
console.log(son.getName())   // son.getName is not a function

缺点:父类原型链上的属性和方法无法获取

三、组合继承(伪经典继承)

function Father(name) {
    this.name = name;
    this.color=['red','blue'];
}
Father.prototype.getName = function() {
    console.log(this.name)
}
function Child(name) {
    Father.apply(this, arguments);
}
Child.prototype = new Father();
Child.prototype.constructor = Child;
var son = new Child('ming');
console.log(son.color);
son.color.push('white')   
var son2 = new Child('wei');
console.log(son2.color)     //['red','blue']

基本ok,除了new Father()那个地方会多写一遍属性和方法,差不多还行

四、原型式继承(道爷-2006)

var Person = {
    name: 'ming',
    color: ['red', 'blue']
}
function object(obj) {
    function F() { };
    F.prototype = obj;
    return new F();
}
var son1 = object(Person);
var son2 = object(Person);
son1.name = 'wei';
son1.color = ['white'];
console.log(son2.color);  // ['red','blue','white']

缺点很明显:
1,原型实例指向的引用相同,可能存在篡改
2,不能传递参数
另:object方法已经由Object.create()实现

五、寄生式继承,(道爷有点皮)

创建一个函数,在内部构造新的属性和方法,以增强对象(原型式继承的加强版)

var Person = {
    name: 'ming',
    color: ['red', 'blue']
}
function object(obj) {
    function F() { };
    F.prototype = obj;
    return new F();
}
function createSon(obj) {
    var son = object(obj);
    console.log(son)
    son.say = function () {
        console.log('Hello,' + this.name)
    }
    return son;
}
var son1 = createSon(Person);
console.log(son1.name)

缺点很明显:
1,原型实例指向的引用相同,可能存在篡改
2,不能传递参数

六、寄生组合式继承(借用构造函数继承+寄生式继承)

function object(obj) {
    function F() { };
    F.prototype = obj;
    return new F();
}
function inheritPerson(Person, Son) {
    var pro = object(Person.prototype);
    Son.prototype.constructor = Son;
    Son.prototype = pro;
}
function Person(name) {
    this.name = name;
    this.color = ['red', 'blue'];
}
Person.prototype.say = function () {
    console.log('Hello,' + this.name)
}
function Son(name, age) {
    Person.call(this, name);
    this.age = age;
}
inheritPerson(Person, Son);
Son.prototype.getAge = function () {
    console.log(this.age);
}
var child1 = new Son('ming', 20);
var child2 = new Son('wei', 30);
child1.say()  // ming
child1.color.push('white');
console.log(child2.color)  //['red','blue']

这个是es5的终极解决方案

js-对象几种继承方式

七、混入方式继承多个对象

function Father1(name) { this.name = name }
function Father2(age) { this.age = age }
function Son(name, age) {
    Father1.call(this, name);
    Father2.call(this, age);
}
Son.prototype = Object.create(Father1.prototype);
Object.assign(Father1.prototype, Father2.prototype);
Son.prototype.constructor = Son;
var son1 = new Son('ming', 20);
console.log(son1)

这个实际上是寄生组合式继承的加强版

八、class继承

class Person {
    constructor(name) {
        this.name = name
    }
    say() {
        console.log(this.name)
    }
}
class Son extends Person {
    constructor(name) {
        super(name)
    }
}

使用babel转义为es5之后:

"use strict";
function _inheritsLoose(subClass, superClass) {
    subClass.prototype = Object.create(superClass.prototype);
    subClass.prototype.constructor = subClass;
    subClass.__proto__ = superClass;
}
var Person =
    function () {
        function Person(name) {
            this.name = name;
        }
        var _proto = Person.prototype;
        _proto.say = function say() {
            console.log(this.name);
        };
        return Person;
    }();
var Son =
    function (_Person) {
        _inheritsLoose(Son, _Person);
        function Son(name) {
            return _Person.call(this, name) || this;
        }
        return Son;
    }(Person);

总结

  1. 类方法调用时不会变量提升:
var p = new P(); // Cannot access 'P' before initialization class P{}
  1. es6的继承,实际上是先创建父类的实例对象this,然后再用子类的构造函数修改this,因此在子类的contructor中要调用父类的super(),否则要报错。
上一篇:P3469 [POI2008]BLO-Blockade 题解


下一篇:洛谷P2015 二叉苹果树