淺談ES6類

ECMAScript6中終於引入了類的特性,在此以前只能經過其餘方法定義並關聯多個類似的對象,固然了,ES6中的類與其餘語言中的仍是不太同樣,其語法的設計實際上借鑑了JavaScript的動態性,本文檔簡單介紹一下ES6及其新特性。javascript

類的聲明

ES6中聲明一個類,首先編寫class關鍵字,緊跟着是類的名字,其餘部分的語法相似於對象字面量方法的簡寫形式,可是不須要子類的各元素之間使用逗號分隔,請看下面這段簡單的類聲明代碼:java

class PersonClass{
        constructor(name){
            this.name = name
        }
        sayName(){
            return this.name
        }
    }

    let person = new PersonClass('xiaoMing')
    console.log(person.sayName())                        // 'xiaoMing'
    console.log(person instanceof PersonType)           //true
    console.log(person instanceof Object)              //true

    console.log(typeof PersonClass)                    // function
    console.log(typeof PersonClass.prototype.sayName) // function

對比類聲明語法定義PersonClass的行爲與ES5以前用構造函數構建近似類過程類似,可是仍有不少差別:es6

1.  函數聲明能夠被提高,而類聲明與let聲明相似,不能被提高;真正執行聲明語句以前,他們會一直存在於臨時死區中。  
2.  類聲明中的全部代碼將自動運行在嚴格模式下,並且沒法強行讓代碼脫離嚴格模式執行。
3.  在自定義類型,須要經過Object.defineProperty()方法手工指定某個方法爲不可枚舉,而在類中,全部的方法都是不可枚舉的。
4.  每一個類都有一個名爲[Constructor]]的內部方法,經過關鍵字new調用方那些不含[Constructor]]的方法會致使程序拋出錯誤。
5.  使用關鍵字new之外的方式調用類的構造函數會致使程序拋出錯誤。
6.  在類中修改類名會致使程序報錯。

類不只僅能夠經過聲明實現,還可使用類表達式 ,類表達式又分爲匿名類表達式和命名類表達式,具體語法以下所示:編程

//匿名類表達式
    let PersonClass = class{
        constructor(name){
            this.name = name
        }
        sayName(){
            console.log(this.name)
        }
    }
//命名錶達式
    let PersonClass = class PersonClass2{
        constructor(name){
            this.name = name
        }
        sayName(){
            console.log(this.name)
        }
    }
    console.log(typeof PersonClass)          // function
    console.log(typeof PersonClass2)        // undefined

二者除了命名錶達式需在關鍵字class後添加一個標識符外,並沒有其餘差異,可是注意typeof PersonClass2 輸出的是undefined,這是由於PersonClass2只存在於類定義中,而在類的外部,其實並不存在一個名爲PersonClass2的綁定。下邊咱們用一段沒有使用關鍵字class的等價聲明來了解這背後的原理:安全

let PersonClass = (function () {
        const PersonClass2 = function (name) {
            if (typeof new.target === "undefined") {      //類與構造函數差別的第五條
                throw new Error("必須經過new關鍵字調用構造函數")
            }
            this.name = name
        }
        Object.defineProperty(PersonClass2.prototype, 'sayName', {
            value: function () {
                if (typeof new.target !== "undefined") {    //類與構造函數差別的第四條
                    throw new Error("不可以使用new關鍵字調用該方法")
                }
                console.log(this.name)
            },
            enumerable: false,
            writable: true,
            configurable: true,
        })
        return PersonClass2
    }())

外部做用域中的PersonClasss是用let聲明的,而當即表達式中的PersonClass2是用const聲明的,這也說明了爲何能夠在外部修改類名而內部卻不可修改,且PersonClass2只能在類內部使用。函數

類的特色

下邊簡單介紹一下類中的幾個小特性this

  • 一級公民類
    在編程中,能被當作值使用的就成爲一級公民,意味着它能夠被當作參數傳給函數,能夠做爲函數返回值,能用來賦值給變量,JS的類也能夠被當成值使用,就是一級公民類。
  • 訪問屬性
    自有屬性須要在類構造器中建立,而類還容許你在原型上定義訪問器屬性。爲了建立一個getter ,要使用 get 關鍵字,並要與後方標識符之間留出空格;建立 setter 用相同方式,只是要換用 set 關鍵字。
  • 需計算成員名
    類方法與類訪問器屬性也都能使用需計算的名稱。語法相同於對象字面量中的需計算名稱:無須使用標識符,而是用方括號來包裹一個表達式。
  • 生成器方法
    可使用 Symbol.iterator 來定義生成器方法,從而定義出類的默認迭代器。
  • 靜態成員
    ES6 類的靜態成員的建立,只要在方法與訪問器屬性的名稱前添加正式的 static 標註。你能在類中的任何方法與訪問器屬性上使用 static 關鍵字,惟一限制是不能將它用於 constructor 方法的定義。

繼承與派生類

首先咱們來看下ES6中是怎麼實現繼承的:prototype

class Rectangle(){
        constructor(length,width){
            this.length = length
            this.width = width
        }
        getArea(){
            return this.length * this.width
        }
    }

    class Square extends Rectangle {
        constructor(length){
            //等價於Rectangle.call(this,length,length)
            super(length,length)
        }
    }
    var square = new Square(3)
    console.log(square.getArea())              //9
    console.log(square instanceof Suqare)     //true
    console.log(square instanceof Rectangle) //true

ES5中Square繼承自Rectangle,爲了這樣作,必須建立自Rectangle.prototype的新對象重寫Square.prototype並調用Rectangle。call()方法,這些步驟很容易讓人感到困惑,並在這裏犯錯。ES6類的出現讓咱們輕鬆實現了繼承功能,使用extends關鍵字能夠指定類繼承的函數,繼承自其餘類的類被稱做派生類,若是在派生類中指定了構造函數則必需要調用super(),經過調用super()方法便可訪問基類的構造函數,原型會自動調整,若是不這樣作,程序就會報錯。若是選擇不適用構造函數,則當建立新的類實例時會自動調用super()並傳入全部參數。舉個例子,一下兩個類徹底相同:設計

class Square extends Rectangle{
        //沒有構造函數
    }

    clas Square extends Rectangle{
        constructor(...args){
            super(...args)
        }
    }

派生類的特性

派生類除了上述的特徵外,還有一些其餘的特性:code

  1. 派生類中的方法總會覆蓋基類中的同名方法。
  2. 若是基類中有靜態成員,那麼這些靜態成員在派生類中也可用。
  3. 只要表達式能夠被解析爲一個函數而且具備[[constructor]]屬性和原型,就能夠用extends進行派生。
  4. ES6支持內建對象的繼承。

ES6 的類讓 JS 中的繼承變得更簡單,是javaScript新特性的一個重要組成部分,這一特性提供了一種更簡潔的語法和更好的功能,可讓你經過一個安全、一致的方法來自定義對象類型。

相關文章
相關標籤/搜索