亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

ES6 系列之 Babel 是如何編譯 Class 的(上)

shadajin / 2925人閱讀

摘要:前言在了解是如何編譯前,我們先看看的和的構(gòu)造函數(shù)是如何對應(yīng)的。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用也可以執(zhí)行。該函數(shù)的作用就是將函數(shù)數(shù)組中的方法添加到構(gòu)造函數(shù)或者構(gòu)造函數(shù)的原型中,最后返回這個(gè)構(gòu)造函數(shù)。

前言

在了解 Babel 是如何編譯 class 前,我們先看看 ES6 的 class 和 ES5 的構(gòu)造函數(shù)是如何對應(yīng)的。畢竟,ES6 的 class 可以看作一個(gè)語法糖,它的絕大部分功能,ES5 都可以做到,新的 class 寫法只是讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法而已。

constructor

ES6 中:

class Person {
    constructor(name) {
        this.name = name;
    }

    sayHello() {
        return "hello, I am " + this.name;
    }
}

var kevin = new Person("Kevin");
kevin.sayHello(); // hello, I am Kevin

對應(yīng)到 ES5 中就是:

function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function () {
    return "hello, I am " + this.name;
};

var kevin = new Person("Kevin");
kevin.sayHello(); // hello, I am Kevin

我們可以看到 ES5 的構(gòu)造函數(shù) Person,對應(yīng) ES6 的 Person 類的 constructor 方法。

值得注意的是:類的內(nèi)部所有定義的方法,都是不可枚舉的(non-enumerable)

以上面的例子為例,在 ES6 中:

Object.keys(Person.prototype); // []
Object.getOwnPropertyNames(Person.prototype); // ["constructor", "sayHello"]

然而在 ES5 中:

Object.keys(Person.prototype); // ["sayHello"]
Object.getOwnPropertyNames(Person.prototype); // ["constructor", "sayHello"]
實(shí)例屬性

以前,我們定義實(shí)例屬性,只能寫在類的 constructor 方法里面。比如:

class Person {
    constructor() {
        this.state = {
            count: 0
        };
    }
}

然而現(xiàn)在有一個(gè)提案,對實(shí)例屬性和靜態(tài)屬性都規(guī)定了新的寫法,而且 Babel 已經(jīng)支持?,F(xiàn)在我們可以寫成:

class Person {
    state = {
        count: 0
    };
}

對應(yīng)到 ES5 都是:

function Person() {
    this.state = {
        count: 0
    };
}
靜態(tài)方法

所有在類中定義的方法,都會被實(shí)例繼承。如果在一個(gè)方法前,加上 static 關(guān)鍵字,就表示該方法不會被實(shí)例繼承,而是直接通過類來調(diào)用,這就稱為“靜態(tài)方法”。

ES6 中:

class Person {
    static sayHello() {
        return "hello";
    }
}

Person.sayHello() // "hello"

var kevin = new Person();
kevin.sayHello(); // TypeError: kevin.sayHello is not a function

對應(yīng) ES5:

function Person() {}

Person.sayHello = function() {
    return "hello";
};

Person.sayHello(); // "hello"

var kevin = new Person();
kevin.sayHello(); // TypeError: kevin.sayHello is not a function
靜態(tài)屬性

靜態(tài)屬性指的是 Class 本身的屬性,即 Class.propName,而不是定義在實(shí)例對象(this)上的屬性。以前,我們添加靜態(tài)屬性只可以這樣:

class Person {}

Person.name = "kevin";

因?yàn)樯厦嫣岬降奶岚?,現(xiàn)在可以寫成:

class Person {
  static name = "kevin";
}

對應(yīng)到 ES5 都是:

function Person() {};

Person.name = "kevin";
new 調(diào)用

值得注意的是:類必須使用 new 調(diào)用,否則會報(bào)錯(cuò)。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用 new 也可以執(zhí)行。

class Person {}

Person(); // TypeError: Class constructor Foo cannot be invoked without "new"
getter 和 setter

與 ES5 一樣,在“類”的內(nèi)部可以使用 get 和 set 關(guān)鍵字,對某個(gè)屬性設(shè)置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為。

class Person {
    get name() {
        return "kevin";
    }
    set name(newName) {
        console.log("new name 為:" + newName)
    }
}

let person = new Person();

person.name = "daisy";
// new name 為:daisy

console.log(person.name);
// kevin

對應(yīng)到 ES5 中:

function Person(name) {}

Person.prototype = {
    get name() {
        return "kevin";
    },
    set name(newName) {
        console.log("new name 為:" + newName)
    }
}

let person = new Person();

person.name = "daisy";
// new name 為:daisy

console.log(person.name);
// kevin
Babel 編譯

至此,我們已經(jīng)知道了有關(guān)“類”的方法中,ES6 與 ES5 是如何對應(yīng)的,實(shí)際上 Babel 在編譯時(shí)并不會直接就轉(zhuǎn)成這種形式,Babel 會自己生成一些輔助函數(shù),幫助實(shí)現(xiàn) ES6 的特性。

我們可以在 Babel 官網(wǎng)的 Try it out 頁面查看 ES6 的代碼編譯成什么樣子。

編譯(一)

ES6 代碼為:

class Person {
    constructor(name) {
        this.name = name;
    }
}

Babel 編譯為:

"use strict";

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

var Person = function Person(name) {
    _classCallCheck(this, Person);

    this.name = name;
};

_classCallCheck 的作用是檢查 Person 是否是通過 new 的方式調(diào)用,在上面,我們也說過,類必須使用 new 調(diào)用,否則會報(bào)錯(cuò)。

當(dāng)我們使用 var person = Person() 的形式調(diào)用的時(shí)候,this 指向 window,所以 instance instanceof Constructor 就會為 false,與 ES6 的要求一致。

編譯(二)

ES6 代碼為:

class Person {
    // 實(shí)例屬性
    foo = "foo";
    // 靜態(tài)屬性
    static bar = "bar";

    constructor(name) {
        this.name = name;
    }
}

Babel 編譯為:

"use strict";

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

var Person = function Person(name) {
    _classCallCheck(this, Person);

    this.foo = "foo";

    this.name = name;
};

Person.bar = "bar";
編譯(三)

ES6 代碼為:

class Person {
    constructor(name) {
        this.name = name;
    }

    sayHello() {
        return "hello, I am " + this.name;
    }

    static onlySayHello() {
        return "hello"
    }

    get name() {
        return "kevin";
    }

    set name(newName) {
        console.log("new name 為:" + newName)
    }
}

對應(yīng)到 ES5 的代碼應(yīng)該是:

function Person(name) {
    this.name = name;
}

Person.prototype =  {
    sayHello: function () {
        return "hello, I am " + this.name;
    },
    get name() {
        return "kevin";
    },
    set name(newName) {
        console.log("new name 為:" + newName)
    }
}

Person.onlySayHello = function () {
    return "hello"
};

Babel 編譯后為:

"use strict";

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;
    };
}();

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

var Person = function() {
    function Person(name) {
        _classCallCheck(this, Person);

        this.name = name;
    }

    _createClass(Person, [{
        key: "sayHello",
        value: function sayHello() {
            return "hello, I am " + this.name;
        }
    }, {
        key: "name",
        get: function get() {
            return "kevin";
        },
        set: function set(newName) {
            console.log("new name 為:" + newName);
        }
    }], [{
        key: "onlySayHello",
        value: function onlySayHello() {
            return "hello";
        }
    }]);

    return Person;
}();

我們可以看到 Babel 生成了一個(gè) _createClass 輔助函數(shù),該函數(shù)傳入三個(gè)參數(shù),第一個(gè)是構(gòu)造函數(shù),在這個(gè)例子中也就是 Person,第二個(gè)是要添加到原型上的函數(shù)數(shù)組,第三個(gè)是要添加到構(gòu)造函數(shù)本身的函數(shù)數(shù)組,也就是所有添加 static 關(guān)鍵字的函數(shù)。該函數(shù)的作用就是將函數(shù)數(shù)組中的方法添加到構(gòu)造函數(shù)或者構(gòu)造函數(shù)的原型中,最后返回這個(gè)構(gòu)造函數(shù)。

在其中,又生成了一個(gè) defineProperties 輔助函數(shù),使用 Object.defineProperty 方法添加屬性。

默認(rèn) enumerable 為 false,configurable 為 true,這個(gè)在上面也有強(qiáng)調(diào)過,是為了防止 Object.keys() 之類的方法遍歷到。然后通過判斷 value 是否存在,來判斷是否是 getter 和 setter。如果存在 value,就為 descriptor 添加 value 和 writable 屬性,如果不存在,就直接使用 get 和 set 屬性。

寫在后面

至此,我們已經(jīng)了解了 Babel 是如何編譯一個(gè) Class 的,然而,Class 還有一個(gè)重要的特性就是繼承,Class 如何繼承,Babel 又該如何編譯,歡迎期待下一篇《 ES6 系列之 Babel 是如何編譯 Class 的(下)》

ES6 系列

ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog

ES6 系列預(yù)計(jì)寫二十篇左右,旨在加深 ES6 部分知識點(diǎn)的理解,重點(diǎn)講解塊級作用域、標(biāo)簽?zāi)0?、箭頭函數(shù)、Symbol、Set、Map 以及 Promise 的模擬實(shí)現(xiàn)、模塊加載方案、異步處理等內(nèi)容。

如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,請?wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對作者也是一種鼓勵(lì)。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/99014.html

相關(guān)文章

  • ES6 系列 Babel 如何編譯 Class (下)

    摘要:以上的代碼對應(yīng)到就是調(diào)用父類的值得注意的是關(guān)鍵字表示父類的構(gòu)造函數(shù),相當(dāng)于的。舉個(gè)例子這是因?yàn)樽鳛闃?gòu)造函數(shù)的語法糖,同時(shí)有屬性和屬性,因此同時(shí)存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。 前言 在上一篇 《 ES6 系列 Babel 是如何編譯 Class 的(上)》,我們知道了 Babel 是如何編譯 Class 的,這篇我們學(xué)習(xí) Babel 是如何用 ES5 實(shí)現(xiàn)...

    endiat 評論0 收藏0
  • 揭秘babel魔法class繼承處理2

    摘要:并且用驗(yàn)證了中一系列的實(shí)質(zhì)就是魔法糖的本質(zhì)。抽絲剝繭我們首先看的編譯結(jié)果這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)就是他要繼承的父類,返回一個(gè)構(gòu)造函數(shù)。 如果你已經(jīng)看過第一篇揭秘babel的魔法之class魔法處理,這篇將會是一個(gè)延伸;如果你還沒看過,并且也不想現(xiàn)在就去讀一下,單獨(dú)看這篇也沒有關(guān)系,并不存在理解上的障礙。 上一篇針對Babel對ES6里面基礎(chǔ)class的編譯進(jìn)行了分析。這一篇將...

    BlackHole1 評論0 收藏0
  • 揭秘babel魔法class魔法處理

    摘要:年,很多人已經(jīng)開始接觸環(huán)境,并且早已經(jīng)用在了生產(chǎn)當(dāng)中。我們發(fā)現(xiàn),關(guān)鍵字會被編譯成構(gòu)造函數(shù),于是我們便可以通過來實(shí)現(xiàn)實(shí)例的生成。下一篇文章我會繼續(xù)介紹如何處理子類的并會通過一段函數(shù)橋梁,使得環(huán)境下也能夠繼承定義的。 2017年,很多人已經(jīng)開始接觸ES6環(huán)境,并且早已經(jīng)用在了生產(chǎn)當(dāng)中。我們知道ES6在大部分瀏覽器還是跑不通的,因此我們使用了偉大的Babel來進(jìn)行編譯。很多人可能沒有關(guān)心過,...

    wqj97 評論0 收藏0
  • ES6 系列我們來聊聊裝飾器

    摘要:第二部分源碼解析接下是應(yīng)用多個(gè)第二部分對于一個(gè)方法應(yīng)用了多個(gè),比如會編譯為在第二部分的源碼中,執(zhí)行了和操作,由此我們也可以發(fā)現(xiàn),如果同一個(gè)方法有多個(gè)裝飾器,會由內(nèi)向外執(zhí)行。有了裝飾器,就可以改寫上面的代碼。 Decorator 裝飾器主要用于: 裝飾類 裝飾方法或?qū)傩? 裝飾類 @annotation class MyClass { } function annotation(ta...

    eternalshallow 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<