Javascript面向对象- 继承的几种方式

2018-12-24  本文已影响0人  厦门_小灰灰

原型链

ECMAScript中将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

function SuperType() {
    this.property = true;
    this.colors = ["a", "b"];
}

SuperType.prototype.getSuperValue = function(){
    console.log(this.property);
};

function SubType() {
    this.subProperty = false;
}

SubType.prototype = new SuperType();
// SubType.prototype = Object.create(SuperType.prototype);

SubType.prototype.getSubValue = function(){
    console.log(this.subProperty);
};

var instance = new SubType();
instance.getSuperValue();

结果:


B2141495-7F1C-459E-AD14-7FCD44D622C3.png

上面的例子中,instance指向SubType的原型,SubType的原型又指向SuperType的原型。getSuperValue()方法仍然还在SuperType.prototype中,但property则位于SubType.prototype中。这是因为prototype是一个实例属性,而getSuperValue()则是一个原型方法。

注意:原型链虽然很强大,可以实现继承,但存在两个主要的问题。
(1)包含引用类型值的原型属性会被所有实例共享,这会导致对一个实例的修改会影响另一个实例。
(2)在创建子类型的实例时,不能向超类型的构造函数中传递参数。由于这两个问题的存在,实践中很少单独使用原型链。

function SuperType() {
        this.property = true;
        this.colors = ["a", "b"];
}

SuperType.prototype.getSuperValue = function(){
        console.log(this.property);
};

function SubType() {
        this.subProperty = false;
}

SubType.prototype = new SuperType();
// SubType.prototype = Object.create(SuperType.prototype);

SubType.prototype.getSubValue = function(){
        console.log(this.subProperty);
};

var instance1 = new SubType();
instance1.colors.push("c");

console.log(instance1.colors);

var instance2 = new SubType();
console.log(instance2.colors);

结果:


CC1EB7F7-4033-4DA9-9599-20DCE1A97259.png

会发现引用类型值的原型属性会被所有实例共享。

function SuperType() {
        this.colors = ["a", "b"];
}

function SubType() {
        SuperType.call(this);
        this.subProperty = false;
}

var instance1 = new SubType();
instance1.colors.push("c");
console.log(instance1.colors);

var instance2 = new SubType();
console.log(instance2.colors);

结果:


BE163E43-7D13-4F68-8F95-31F7D7D81B56.png

上面例子中,通过使用call()方法(或者apply()方法),在新创建的SubType实例的环境下调用了SuperType构造函数。这样一来就会在新的SubType对象上执行SuperType()函数中定义的所有对象初始化代码。结果,SubType的每个实例都会有自己的colors属性副本。

相对于原型链而言,借用构造函数可以在子类型构造函数中向超类型构造函数传递参数。如下例子

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

function SubType() {
        SuperType.call(this, "Lee");
        this.age = 28;
}

var instance1 = new SubType();
console.log(instance1.name);
console.log(instance1.age);

结果:


A9B61920-3DF3-4F8F-B8EA-D6EB0D4A097C.png

借用构造函数存在两个问题:
(1)无法避免构造函数模式存在的问题,方法都在构造函数中定义,因此无法复用函数。
(2)在超类型的原型中定义的方法,对子类型而言是不可见的。因此这种技术很少单独使用。

组合继承,指的是将原型链和借用构造函数的技术组合到一起。思路是使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有它自己的属性。以下例子充分说明了这一点

function SuperType(name) {
    this.name = name;
    this.colors = ["a", "b"];
}

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

function SubType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}

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

var instance1 = new SubType("Lee", 28);
instance1.colors.push("c");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("Hui", 27);
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

结果:


3C91027C-32B2-4C26-ADA3-5F6764A929D9.png

这个例子中,两个实例既分别拥有自己的属性,包括colors属性,又可以使用相同的方法。

组合继承避免了原型链和借用构造函数的缺点,融合了他们的优点,是JavaScript中最常用的继承模式。
缺点:实际上子类上会拥有超类的两份属性,只是子类的属性覆盖了超类的属性

function objectCreate(obj){
  function F(){}
  F.prototype = obj
  return new F()
}

直接通过对象生成一个继承该对象的对象,但是不是类式继承,而是原型式基础,缺少了类的概念。

function objectCreate(obj){
  function F(){}
  F.prototype = obj
  return new F()
}
function createSubObj(superInstance){
  var clone = objectCreate(superInstance)
  clone.property = 'Sub Property'
  return clone
}

原型式继承的一种拓展,但是依旧没有类的概念。

function inheritPrototype(Super,Sub){
  var superProtoClone = Object.Create(Super.prototype)
  superProtoClone.constructor = Sub
  Sub.prototype = Super
}
function Sub(){
  Super.call()
  Sub.property = 'Sub Property'
}
inheritPrototype(Super,Sub)

完美实现继承,解决了组合式继承带两份属性的问题,过于繁琐,故不如组合继承。

上一篇下一篇

猜你喜欢

热点阅读