Как Babel из серии ES6 компилирует класс (часть 1)

внешний интерфейс GitHub Promise Babel
Как Babel из серии ES6 компилирует класс (часть 1)

предисловие

Прежде чем понять, как Babel компилирует классы, давайте посмотрим, как классы ES6 соответствуют конструкторам ES5. В конце концов, класс ES6 можно рассматривать как синтаксический сахар, и большинство его функций может выполнять ES5.Новый метод написания класса просто делает метод написания прототипа объекта более понятным и более похожим на синтаксис объектно-ориентированного программирования.

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

Соответствует 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

Мы видим, что конструктор Person из ES5 соответствует методу конструктора класса Person из ES6.

Стоит отметить, что:Все методы, определенные внутри класса, являются неперечислимыми (неперечислимыми)

Взяв пример выше, в ES6:

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

Однако в ES5:

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

свойства экземпляра

Раньше мы определяли свойства экземпляра, которые могли быть записаны только в методе-конструкторе класса. Например:

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

Однако теперь есть предложение, определяющее новый способ записи как свойств экземпляра, так и статических свойств, и Babel уже поддерживает его. Теперь мы можем написать:

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

ES5 соответствуют:

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

статический метод

Все методы, определенные в классе, будут унаследованы экземпляром. Если ключевое слово static добавлено перед методом, это означает, что метод не будет унаследован экземпляром, а будет вызываться непосредственно через класс, который называется «статическим методом».

В ES6:

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

Person.sayHello() // 'hello'

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

Для ES5:

function Person() {}

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

Person.sayHello(); // 'hello'

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

статические свойства

Статические свойства относятся к свойствам самого класса, а именно к Class.propName, а не к свойствам, определенным в объекте экземпляра (этот). Раньше мы могли добавлять только статические свойства следующим образом:

class Person {}

Person.name = 'kevin';

Из-за предложения, упомянутого выше, теперь его можно записать как:

class Person {
  static name = 'kevin';
}

ES5 соответствуют:

function Person() {};

Person.name = 'kevin';

новый вызов

Стоит отметить: класс должен использовать новый вызов, иначе будет ошибка. Это основное отличие от общего конструктора, который также не является новым.

class Person {}

Person(); // TypeError: Class constructor Foo cannot be invoked without 'new'

геттеры и сеттеры

Как и в ES5, ключевые слова get и set можно использовать внутри «класса», чтобы установить функцию сохранения значения и функцию значения функции для свойства, а также перехватить поведение доступа к свойству.

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

Соответствует 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

Вавилонская подборка

Пока мы уже знаем, как ES6 и ES5 соответствуют методам "класса". На самом деле Babel не будет напрямую преобразовывать в эту форму при компиляции. Babel сам сгенерирует некоторые вспомогательные функции, помогающие реализовать характеристики ES6.

Мы можем найти его на официальном сайте Babel. Try it out См. страницу, чтобы узнать, во что компилируется код ES6.

Компиляция (1)

Код 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 Выше мы также говорили, что класс должен вызываться по new, иначе будет сообщено об ошибке.

когда мы используемvar person = Person()При вызове в форме это указывает на окно, поэтомуinstance instanceof Constructorбудет ложным, в соответствии с требованиями ES6.

Компиляция (2)

Код ES6:

class Person {
    // 实例属性
    foo = 'foo';
    // 静态属性
    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';

Компиляция (3)

Код 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)
    }
}

Код, соответствующий ES5, должен быть:

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 генерирует вспомогательную функцию _createClass, которая передает три параметра: первый — это конструктор, которым в данном примере является Person, второй — массив функций, которые нужно добавить в прототип, первые три — это массив функции, которые нужно добавить в сам конструктор, то есть все функции, добавляющие ключевое слово static. Функция этой функции состоит в том, чтобы добавить методы из массива функций в конструктор или прототип конструктора и, наконец, вернуть конструктор.

В нем генерируется еще одна вспомогательная функция defineProperties для добавления свойств с помощью метода Object.defineProperty.

По умолчанию enumerable имеет значение false, а configurable — true.Это также подчеркнуто выше, чтобы предотвратить обход таких методов, как Object.keys(). Затем оцените, является ли это геттером и сеттером, оценив, существует ли значение. Если есть значение, добавьте значение и записываемые атрибуты в дескриптор, если нет, используйте атрибуты get и set напрямую.

написать на обороте

До сих пор мы понимали, как Babel компилирует класс. Однако другой важной особенностью класса является наследование, как наследовать от класса и как компилировать Babel. Добро пожаловать в следующую статью «Как Babel из серии ES6 компилирует класс» (ниже )"

серия ES6

Адрес каталога серии ES6:GitHub.com/ в настоящее время имеет бриз…

Ожидается, что в серии ES6 будет написано около 20 статей, направленных на углубление понимания некоторых точек знаний ES6, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.

Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.