JS中的继承

我心飞翔 分类:javascript

继承

构造函数、原型和实例的关系

  1. 每个构造函数都有一个原型对象
  2. 原型有个属性指回构造函数
  3. 实例有个内部指针指向原型

原型链

  • 如果原型是另一个类型的实例,那就说明这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样子就构成了一个原型链。

组合式继承

  • 综合了原型链和盗用构造函数,将两者的优点集中了起来。
  • 基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。
  • 这样既可以把方法在原型上以实现重用,又可以让每个实例都有自己的属性
//组合继承
function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function() {
    console.log(this.name);
}

function SubType(name, age) {
    //继承属性
    SuperType.call(this, name);

    this.age = age;
}

SubType.prototype = new SuperType();

SuperType.prototype.sayAge = function() {
    console.log(this.age);
}

let instance1 = new SubType("n1", 19);
instance1.colors.push("black");
console.log(instance1.colors); //["red", "blue", "green", "black"]
instance1.sayName(); //n1
instance1.sayAge(); //19

let instance2 = new SubType("Greg", 27);
console.log(instance2.colors); //["red", "blue", "green"]
instance2.sayName(); //Greg
instance2.sayAge(); //27
 

原型式继承

  • 使用的情况:你有一个对象,想在它的基础上再创建一个新的对象。
  • es5通过增加Object.create()方法将原型式继承的概念规范化,这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的object()方法效果相同
  • 原型式继承非常适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合
let person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

let anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

let yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

console.log(person.friends); //"Shelby", "Court", "Van", "Rob", "Barbie"

//第二个参数
let person1 = Object.create(person, {
    name: {
        value: "Grat"
    }
})
console.log(person1.name);//"Grat"
 

寄生式继承

  • 寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象
  • 寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景。
let person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

function createAnther(original) {
    let clone = Object.create(original);
    clone.sayHi = function() {
        console.log("hi");
    };
    return clone;
}

let anotherPerson = createAnther(person);
anotherPerson.sayHi(); //hi
 

寄生式组合继承

  • 组合式继承继承存在效率问题。最主要的效率问题就是父类的构造函数始终会被调用两次:一次在创建子类原型时调用,另一次是在子类构造函数中调用
  • 本质上,子类原型最终是要包含超类对象的所有实例,子类构造函数只要在执行时重写自己的原型就行了。
function inheritPrototype(subType, superType) {
    let prototype = Object.create(superType.prototype); //创建对象
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function SuperType(name) {
    this.name = name;
    this.color = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function() {
    console.log(this.name);
}

function SubType(name, age) {
    SuperType.call(this, name); //第二次调用SuperType()
    this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {
    console.log(this.age);
}
 
  • 原型链仍然保持不变,因此instanceof操作符和isPrototypeOf()方法正常有效。寄生式组合继承算是引用类型继承的最佳模式

回复

我来回复
  • 暂无回复内容