javaScript实现继承的几种方法

很多面向对象的语言都接受两种继承:接口继承和实现继承。

前者只继承方法签名,后者继承实际的方法。接口继承在 ECMAScript 中是不可能的,因为函数没有签
名。实现继承是 ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的。
1.原型链继承
通过原型链继承的方式,SubType可以继承SuperType构造函数上的所有属性(自定义的属性&&原型链上的属性)
    function SuperType() { 
      this.property = true; 
    } 
    SuperType.prototype.getSuperValue = function() { 
      return this.property; 
    }; 
    function SubType() { 
      this.subproperty = false; 
    } 
    // 继承 SuperType 
    SubType.prototype = new SuperType(); 
    SubType.prototype.getSubValue = function () {
        return this.subproperty; 
    }; 
    let instance = new SubType(); 
    console.log(instance); 

问题:1.当原型链中包含引用类型的时候,会在所有实例间共享

           2.原型链的第二个问题是,子类型在实例化时不能给父类型的构造函数传参。

2.盗用构造函数

apply()和 call()方法以新创建的对象为上下文执行构造函数
解决了原型链继承中出现引用类型不能在实例间共享的问题
function SuperType() { 
 this.colors = ["red", "blue", "green"]; 
} 
function SubType() { 
 // 继承 SuperType 
 SuperType.call(this); 
} 
let instance1 = new SubType(); 
instance1.colors.push("black"); 
console.log(instance1.colors); // "red,blue,green,black" 
let instance2 = new SubType(); 
console.log(instance2.colors); // "red,blue,green"

并且使用该种方式,也可以解决原型链上不能传参的问题

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

问题: 1.必须在构造函数中声明方法,不能重用 2.子类不能访问父类上面的原型方法

3.组合继承

组合继承通过构造函数的方式继承实例属性,通过原型链继承的方式继承属性和方法,可以让属性在实例间私有,同时可以通过原型链继承的方式实现方法间的共享

组合继承弥补了原型链和盗用构造函数的不足,是 JavaScript 中使用最多的继承模式。而且组合继承也保留了 instanceof 操作符和 isPrototypeOf()方法识别合成对象的能力。
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(); 
SubType.prototype.sayAge = function() { 
 console.log(this.age); 
}; 
let instance1 = new SubType("Nicholas", 29); 
instance1.colors.push("black"); 
console.log(instance1.colors); // "red,blue,green,black" 
instance1.sayName(); // "Nicholas"; 
instance1.sayAge(); // 29 
let instance2 = new SubType("Greg", 27); 
console.log(instance2.colors); // "red,blue,green" 
instance2.sayName(); // "Greg"; 
instance2.sayAge(); // 27

 4.原型式继承

原型式继承非常适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合。属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的。
function object(o) { 
 function F() {} 
 F.prototype = o; 
 return new F(); 
}
let person = { 
 name: "Nicholas", 
 friends: ["Shelby", "Court", "Van"] 
}; 
let anotherPerson = object(person); 
anotherPerson.name = "Greg"; 
anotherPerson.friends.push("Rob"); 
let yetAnotherPerson = object(person); 
// let yetAnotherPerson = Object.create(person);
// 这里的Object.create方法等同于object方法
yetAnotherPerson.name = "Linda"; 
yetAnotherPerson.friends.push("Barbie"); 
console.log(person.friends); // "Shelby,Court,Van,Rob,Barbie"

5.寄生式继承

创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象
function createAnother(original){ 
 let clone = object(original); // 通过调用函数创建一个新对象
 clone.sayHi = function() { // 以某种方式增强这个对象
 console.log("hi"); 
 }; 
 return clone; // 返回这个对象
}
let person = { 
 name: "Nicholas", 
 friends: ["Shelby", "Court", "Van"] 
}; 
let anotherPerson = createAnother(person); 
anotherPerson.sayHi(); // "hi"

6.寄生式组合继承

function inheritPrototype(subType, superType) { 
 let prototype = object(superType.prototype); // 创建对象
 prototype.constructor = subType; // 增强对象 
 subType.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); 
};

7.extends

ES6 类支持单继承。使用 extends 关键字,就可以继承任何拥有[[Construct]]和原型的对象
在类构造函数中使用 super 可以调用父类构造函数。
如果在派生类中显式定义了构造函数,则要么必须在其中调用super(),要么必须在其中返回一个对象。
class Vehicle {} 
// 继承类
class Bus extends Vehicle {} 
let b = new Bus(); 
console.log(b instanceof Bus); // true 
console.log(b instanceof Vehicle); // true 
function Person() {} 
// 继承普通构造函数
class Engineer extends Person {} 
let e = new Engineer(); 
console.log(e instanceof Engineer); // true 
console.log(e instanceof Person); // true

 

posted @ 2021-09-04 10:44  千亿昔  阅读(270)  评论(0编辑  收藏  举报