ES6之class的繼承

class語法爲咱們提供了構造函數的語法糖,響應的,也給咱們提供了ES5經過原型鏈實現繼承提供了extends關鍵字實現繼承。繼承這個概念對面後臺應該也是很是常見。bash

經過extends繼承,語法:數據結構

class User{}函數

class Son extends User{}ui

繼承以後Son可使用User類的全部屬性和方法:this

class User{

    constructor(a){

        this.a = a;

        this.b = 10;

    }

    eat(){

        console.log('user eat');

    }

}

class Son extends User{

    constructor(b, c){

      super(b);

      this.c = c;

    }

    sum(){

        console.log(this.a, this.b, this.c);

    }

}

var son = new Son(1, 2);

son.eat();//user eat

son.sum();//1 10 2
複製代碼

子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類本身的this對象,必須先經過父類的構造函數完成塑造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。spa

若是子類沒有定義constructor方法,這個方法會被默認添加,須要注意的地方是,在子類的構造函數中,只有調用super以後,纔可使用this關鍵字,不然會報錯。這是由於子類實例的構建,基於父類實例,只有super方法才能調用父類實例。靜態方法也會繼承。prototype

經過Object.getPrototypeOf獲取父類:code

class User{}

class Son extends User{}

console.log(Object.getPrototypeOf(Son));//class User{}
複製代碼

Super關鍵字有兩個用法,一個是函數,一個是對象。當作函數的時候只能在子類的構造函數中使用,子類必須調用,也就是constructor裏面,其餘地方會報錯:cdn

class User{}

class Son extends User{

    eat(){

        super();

    }

}

//Uncaught SyntaxError: 'super' keyword unexpected here

複製代碼

做爲對象的時候,普通方法super指向父類的原型對象,在靜態方法中指向父類;對象

class User{

  constructor(){

      this.a = 1;

      this.b = 1;

  }

  eat(){

      console.log(this.b);//10

      return 2

  }

}

class Son extends User{

   constructor(){

       super();

       this.b = 10;

       this.c = 20;

       console.log(super.c);//undefined

       console.log(this.c);//20

   }

   talk(){

       console.log(super.a);//undefined

       console.log(super.eat());//2

   }

}

var son = new Son();

son.talk();
複製代碼

普通方法中,super指向父類原型對象(constructor裏面是實例的屬性),因此調用eat方法能夠,a就獲取不到。若是屬性定義在父類的原型對象上,能夠獲取。子類調用super的時候,this指向當前子類的實例。對super賦值至關於爲this賦值。

靜態方法中,super指向父類,也就是User類:

class User{

    constructor(){

        this.a = 10;

    }

    static eat(val) {

        console.log('static', val);

    }

    eat(val) {

        console.log('instance', val);

    }

    static talk(){

        console.log(this.a);

    }

}



class Son extends User{

    constructor(){

        super();

        this.a = 20;

    }

    static eat(val) {

        super.eat(val);

    }

    eat(val) {

        super.eat(val);

    }

    static talk(){

        super.talk();

    }

}

Son.a = 30;

Son.talk();//30

Son.eat(1); // static 1

var son = new Son();

son.eat(2); // instance 2
複製代碼

子類Static eat方法super指向父類,因此調用父類static eat方法,子類普通方法eat指向父類原型對象,因此調用父類普通方法eat。子類靜態方法super內部this指向當前子類,而不是實例或者原型對象,因此子類Son調用talk方法,輸出的是30。

使用super必須指定是函數仍是對象,不然報錯。

類也是有prototype和__proto__屬性的,相應的構成原型鏈:

子類的__proto__屬性是構造函數的繼承,指向父類

子類的prototype屬性的__proto__屬性,表示方法的繼承,指向父類的prototype。

class User{}

class Son extends User{}

console.log(Son.__proto__ === User); // true

console.log(Son.prototype.__proto__ === User.prototype); // true
複製代碼

由於類的繼承是經過setPrototypeOf。

子類實例的__proto__屬性的__proto__屬性,指向父類實例的__proto__屬性。也就是說,子類的原型的原型,是父類的原型:

class User{}

class Son extends User{}

console.log(Son.__proto__ === User.__proto__); // false

console.log(Son.__proto__.__proto__ === User.__proto__); // true
複製代碼

原生的構造函數Boolean()、Number()、String()、Array()、Date()、Function()、RegExp()、Error()、Object()在ES5以前是沒法繼承的,ES6能夠自定義原生數據結構:

class MyArray extends Array {

    constructor(...args) {

        super(...args);

    }

}

var arr = new MyArray();
複製代碼

Misin模式就是把多個對象合成一個新的對象,新對象有各個組成的接口:

var a = {}

var b = {}

var c = {...a, ...b}
複製代碼

阮大神提供了class的Mixin:

function mix(...mixins) {

    class Mix {

        constructor() {

            for (let mixin of mixins) {

                copyProperties(this, new mixin()); // 拷貝實例屬性

            }

        }

    }

    for (let mixin of mixins) {

        copyProperties(Mix, mixin); // 拷貝靜態屬性

        copyProperties(Mix.prototype, mixin.prototype); // 拷貝原型屬性

    }

    return Mix;

}

function copyProperties(target, source) {

    for (let key of Reflect.ownKeys(source)) {

        if ( key !== 'constructor'

            && key !== 'prototype'

            && key !== 'name'

        ) {

            let desc = Object.getOwnPropertyDescriptor(source, key);

            Object.defineProperty(target, key, desc);

        }

    }

}
複製代碼

使用:

class DistributedEdit extends mix(Loggable, Serializable) {// ...}
複製代碼

建議可使用了看看打印的數據。

相關文章
相關標籤/搜索