ES6 Class類

ES6 Class類

ES6中class是基於原型的繼承的語法糖,提供更加清晰的語法來建立對象和原型。

聲明和定義

es5 聲明一個構造函數:javascript

function Student(name, age) {
    this.name = name;
    this.age = age;
}

Student.prototype.getInfo = function() {
    return '{name:' + this.name + ',age:' + this.age + '}';
}

Student.prototype.setInfo = function(name, age) {
    this.name = name;
    this.age = age;
}

var p = new Student('nico', 1);
p.getInfo(); //{name:nico,age:1}
p.setInfo('siip', 10);
p.getInfo(); //{name:siip,10}

es6 聲明一個類:java

class Student {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    getInfo() {
        return `{name:${this.name},age:${this.age}}`;
    }
    setInfo(name, age) {
        this.name = name;
        this.age = age;
    }
}
let p = new Student('nico', 1);
p.setInfo('siip', 10);
p.getInfo();//{name:siip,10}

以上二者相比之下,很能夠看出,es6類函數比es5構造函數,代碼量更少,而且結構層次更加簡潔明瞭。es6

有些地方須要注意的是:express

  1. es5存在變量提高(var xxx,function xxx(){})
  2. es6不存在變量提高(const,let,class)

Class 方法

constructorbabel

constructor是默認的方法,就算在聲明類函數時沒有寫constructor方法,在實例化時會自動添加上一個空的constructor函數

class Student {
    constructor() {
        this.desc = 'test';
    }
}

經過babel轉碼:this

function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var Student = function Student() {
        _classCallCheck(this, Student);//類不能直接被調用,只能經過new實例化

        this.desc = 'test';
    };

constructor方法指向自身,在一個類中只能有一個名爲 「constructor」 的特殊方法。es5

Student === Student.prototype.constructor;//true

staticprototype

簡述:顧名思義這是一個靜態方法,就是不須要實例化類就能夠調用的方法, 實例化對象不能繼承靜態方法。code

class Student {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    static ageFilter(...args) {
        let stuAge = args;
        let arr = [];

        for (let i = 0; i < stuAge.length; i++) {
            if (stuAge[i].age > 12) {
                arr.push(stuAge[i])
            }
        }
        return arr;
    }
    getInfo() {
        return `{name:${this.name},age:${this.age}}`;
    }
    setInfo(name, age) {
        this.name = name;
        this.age = age;
    }
}
Student.ageFilter({
    name: 'a',
    age: 1
}, {
    name: 'b',
    age: 14
});//{name: "a", age: 14}

靜態函數的this指向類函數自身,當this沒有指明被誰調用時,this爲undefined

咱們將上面代碼用babel編譯,從結果上看:

var _createClass = function() {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }
        return function(Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

從代碼能夠看出,靜態方法與類函數方法的區別是:當用Object.defineProperty去定義對象屬性時傳入的對象不一樣,一個傳入的是構造函數的原型,另外一個是傳入構造函數。

es6當前還不支持靜態屬性

extends

關鍵字在類聲明或類表達式中用於建立一個類做爲另外一個類的一個子類
class Student {
    constructor(name = null, age = null) {
        this.name = name;
        this.age = age;
    }
    getInfo() {
        return `{name:${this.name},age:${this.age}}`;
    }
    setInfo(name, age) {
        this.name = name;
        this.age = age;
    }
}

class Citizen extends Student {
    constructor(name, age) {
        super(name, age);
        this.name = 123;
    }
}
let stu = new Citizen('siip', '25');
stu.getInfo(); //{name:siip,age:25}

能夠看到子類能夠調用父類上的方法和屬性,當使用extends繼承父類時,子類constructor和super和被默認添加上,而且在構造函數內,只有調用了super函數後才能使用this,不然會拋出ReferenceError錯誤

constructor() {
        this.name = 'xxx'
         super()
      }//ReferenceError

super

  • super可做爲一個函數使用
  • super可做爲一個對象使用

下面一個子類繼承父類的Math的方法:

function MathFns() {
    this.status = 'Father'
}
MathFns.prototype = Math;

class Max extends MathFns {
    constructor() {
        super();
    }
    static base() {
        return super.max();
    }
}
let m = new MathFns();
m; //{status: "Father"}
m.max(1, 2);//2

咱們能夠經過babel編譯,嘗試去理解es6的繼承,

function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });

    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;

}

這個封裝繼承函數,主要實現的功能是,子類原型指向父類,原型構造器指向自身,而後再經過隱式原型鏈指向父類函數,這樣子類被實例化後的對像就能使用父類原型鏈上的方法以及經過隱式原型鏈訪問到父類的屬性。

總結

總的來看,es6的class類其實是基於原型鏈和繼承作的一層封裝,它的結構層次相對於es5原型鏈寫法更加清晰明瞭,代碼量更少。class類主要內容是構造函數、靜態方法、繼承。

  1. 構造函數

    • 一個類裏,必有一個constructor函數,默認。
    • 類不存在變量提高
    • 一個類裏只能有一個constructor函數
    • constructor函數指向類自身
  2. 靜態方法

    • 靜態函數的this指向類函數自身,當this沒有指明被誰調用時,this爲undefined
    • 在同一個類中的一個靜態方法調用另外一個靜態方法
    • 類實例化對象不能調用類靜態方法
  3. 繼承

    • 子類繼承父類的屬性和方法
    • 在子類繼承父類,子類的構造函數中要先調用super函數,才能使用this
    • super能夠做爲函數或對象調用,但指向都是子類
相關文章
相關標籤/搜索