天天看點

JavaScript幾種繼承方式

繼承,是面向對象的,通過繼承,我們更好的服用以前的代碼,提升開發的效率和縮短開發的周期

其實,繼承就是讓子類具有父類的各種方法和屬性,而不需要在子類中重新定義和父類一樣的方法和屬性。當然,在子類中是可以定義一些父類本身沒有的屬性和方法的。繼承在程式設計中并不難了解。

  1. 那麼在JavaScript中的繼承,有多少中方式呢?
  2. es6的extends關鍵字使用了哪一種繼承方式呢?

第一種繼承方式:原型鍊繼承

在原型鍊繼承裡涉及到構造函數、原型和執行個體;

構造函數都有一個原型對象,而原型對象又包含了一個指向構造函數的指針。

如下代碼:

function SuperType() {
    this.name = "duxinyue"
    this.property = "SuperType";
}
SuperType.prototype.getSupertyValue = function () {
    return this.property;
}

function SubType() {
    // this.name = "qingzhuyue"
    this.subproperty = "SubType";
}

// 繼承SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
    return this.subproperty;
}

const instance = new SubType();
const instance1 = new SuperType();
instance1.name = "鍍鋅不得不"
console.log(instance.getSupertyValue()); // SuperType
console.log(instance.getSubValue());

console.log(instance.name);

console.log(instance1.name);      

第二種方式:構造函數繼承(借助call)

function Parent1() {
    this.name = "讀心悅";
}

Parent1.prototype.getName = function () {
    return this.name;
}

function Child1() {
    Parent1.call(this);
    this.type = "child1";
}

const  child1 = new Child1();
console.log(child1); //  { name: '讀心悅', type: 'child1' }
console.log(child1.getName()) //  child1.getName is not a function
      

在構造函數繼承中,child1繼承了Parent的那麼屬性。但是Parent原型對象上的方法卻沒辦法繼承。

第三種方式:組合繼承(原型繼承和構造函數繼承的組合)

function Parent(){
    this.name = "duxinyue";
    this.play = [1,2,3];
}

Parent.prototype.getName = function(){
     return this.name;
}

function Child(){
    Parent.call(this)
    this.type = "child3"
}

Child.prototype = new Parent();
// 指向自己的構造函數
Child.prototype.constructor = Child;
// 構造函數繼承(借助call)

const c1 = new Child();
const c2 = new Child();

c1.play.push(5);
console.log("c1==",c1);
console.log("c2==",c2);
console.log(c1.getName())
console.log(c2.getName())      

第四種方式:原型式繼承

Object.create(),接受兩個參數,第一個參數是作為新對象原型的對象,第二個參數是新對象定義額外的屬性的對象。

const parent = {
    name:"讀心悅",
    play:[1,2,3,4],
    getName:function(){
        return this.name;
    }
};

console.log(parent.getName());

const p0 = Object.create(parent);
p0.name = "青竹悅";
p0.play.push(90);
console.log(p0.name);//青竹悅
console.log(p0.play);//[ 1, 2, 3, 4, 90 ]

const p1 = Object.create(parent);
console.log(p1.name);//讀心悅
console.log(p1.play);//[ 1, 2, 3, 4, 90 ]

console.log(p0.play === p1.play); // true      

第五種方式:寄生式繼承

const parent1 = {
    name:"duxinyue",
    play:[1,2,3],
    getName:function(){
        return  this.name;
    }
}

function clone(original){
    const clone = Object.create(original);
    clone.getPlay = function(){
        return this.play;
    }

    return clone;
}

const p2 = clone(parent1);
const p3 = clone(parent1);
p2.play.push(100)
console.log(p2.getName()); // duxinyue
console.log(p2.getPlay()); // [ 1, 2, 3, 100 ]
console.log(p3.play);//[ 1, 2, 3, 100 ]      

寄生組合繼承

function clone(parent,child){
    child.prototype = Object.create(parent.prototype);
    child.prototype.constructor = child;
}

function Parent5(){
    this.name = 'duxinyue';
    this.play = [1,2,3];
}

Parent5.prototype.getName = function(){
    return this.name;
}

function Child5(){
    Parent5.call(this);
    return type = "child5";
}

clone(Parent5,Child5);
Child5.prototype.getPlay = function(){
    return this.play;
}

let person1 = new Child5();
let person2 = new Child5();
person2.name = "kkk"
console.log(person1);// { name: 'duxinyue', play: [ 1, 2, 3 ] }
console.log(person2); //  { name: 'kkk', play: [ 1, 2, 3 ] }      

繼續閱讀