JS继承

88 阅读3分钟

原型链继承

就是重写子类的原型对象prototype,令它等于父类的一个实例,这样就可以通过父类的实例,父类的实例可以通过_proto_访问到父类上的方法和属性,实现继承

function Parent()
{
    this.name='jack'
}
function Child()
{
    this.type='child'
}
Child.prototype=new Parent()

就是这样的,但是有三个缺点
1.不能传递参数,如果父类可以传参数
2. 多个子类的实例将共享同一个父类的属性,原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会 在构造函数中定义而不会定义在原型上的原因。在使用原型实现继承时,原型实际上变成了另一个类型 的实例。这意味着原先的实例属性摇身一变成为了原型属性
3.子类的prototype的constructor被污染成Parent

盗用构造函数继承

使用call,在子类构造函数中调用父类构造函数 1.可以传递参数

function SuperType(name){ 
 this.name = name; 
} 
function SubType() { 
 // 继承 SuperType 并传参
 SuperType.call(this, "Nicholas"); 
 // 实例属性
 this.age = 29; 
} 
let instance = new SubType(); 
console.log(instance.name); // "Nicholas"; 
console.log(instance.age); // 29

2.缺点 必须在构造函数中定义函数,此外不能访问父类原型上的方法.

组合式继承

就是原型链方式和盗用构造函数方式的合成

function SuperType(name){
    this.name=name
}
SuperType.prototype.sayName = function() { 
 console.log(this.name); 
};
function SubType(name){
    SuperType.call(this,name);
    this.age=29;
}
SubType.prototype = new SuperType()

有个缺点就是,父类的构造函数使用了两次

原型式继承

他的出发点是即使不自定义类型也可以通过原型实现对象之间的信息共享。 就像一个原对象的一个克隆
缺点是实现的是浅拷贝,数据互通

function object(obj)
{
    f(){};
    f.prototype=obj;
    return new f();
}
let person={
    let name='jack',
    let friends=['a','b','c']
}   
let a = object(person)
a.friends.push('d')
let b = object(person)
b.friends  //['a','b','c','d']

因为都在原型上,所以数据共享,ES5的有一个Object.create(),如果只有一个参数就和上面一样,第二个参数就是新添加的参数.Object.create()的第二个参数与 Object.defineProperties()的第二个参数一样
原型式继承非常适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合。但要记住,属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的。

寄生式继承

创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。基本的寄生继承模式如下:

function createAnother(original){ 
 let clone = object(original); // 通过调用函数创建一个新对象
 clone.sayHi = function() { // 以某种方式增强这个对象
 console.log("hi"); 
 }; 
 return clone; // 返回这个对象
}

缺点和原型式继承差不多

寄生组合式继承

寄生组合式继承,解决了组合式父构造函数调用两次,也可以访问父原型的函数,不用担心原型式继承的数据共享,因为通过prototype继承的都是函数,属性是通过盗用构造函数
寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路是不通过调 用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。说到底就是使用寄生式继承来继承父 类原型,然后将返回的新对象赋值给子类原型。寄生式组合继承的基本模式如下所示: 核心是一个寄生函数

function inheritPrototype(child,parent)
{
    let prototype = Object.create(parent.prototype)//克隆父的prototype
    child.prototype.constructor = child //解决constructor的污染
    child.prototype=prototype //赋值对象
}

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; 
} 

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