class 的基本使用及轉(zhuǎn)換成 es5 的源代碼

class 是基于原型繼承的語法糖,并不是另外的一套規(guī)則

class 與 構(gòu)造函數(shù)的區(qū)別在于,類聲明沒有提升

聲明

類聲明和類表達式的主體都執(zhí)行在嚴格模式下。

// Uncaught ReferenceError: Cannot access 'Person' before initialization
// var p1 = new Person('Tom', 12) 

class Person {
    // constructor 構(gòu)造函數(shù) 一個類只能有一個
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

or

const Person = class {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

實例化

class Person {
    // 公有屬性
    sex = '中性'
    // 私有屬性
    #height = 160

    // constructor 構(gòu)造函數(shù) 一個類只能有一個
    // 一個構(gòu)造函數(shù)可以使用 super 關鍵字來調(diào)用一個父類的構(gòu)造函數(shù)。
    constructor(name, age, height) {
        this.name = name
        this.age = age
        this.#height = height
    }

    // Getter
    get info() {
        console.log('name: ' + this.name + '-- age: ' + this.age)
    }

    // Methods
    log() {
        console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + this.#height)
    }

    // static
    // 靜態(tài)方法 作用于類本身
    // 只有類本身才能調(diào)用
    static getName() {
        console.log(this.name)
    }

    static a = 1
}

const p1 = new Person('Tom', 22, 170)
p1.info
p1.log()
Person.getName()
console.log(Person.a)
console.log(p1.sex)

繼承

// 單繼承
class Man extends Person {
    // 子類中定義了構(gòu)造函數(shù),那么它必須先調(diào)用 super() 才能使用 this 
    constructor(name, age, height, sex) {
        super(name, age, height)
        this.sex = sex
    }

    log() {
        //+ '-- #height: ' + this.#height
        // #height 私有的在這里拿不到
        console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex)
    }
}

const man = new Man('Joe', 10, 90, '男')
man.info
man.log()
Man.getName()
console.log(Man.a)
console.log(man.sex)

Mix-ins

實現(xiàn)多繼承

var calculatorMixin = Base => class extends Base {
  calc() { console.log('calc methods') }
};

var randomizerMixin = Base => class extends Base {
  randomize() { console.log('randomize methods') }
};

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

var bar = new Bar()
bar.randomize()  //  randomize methods
bar.calc()  //  calc methods

通過 Babel 轉(zhuǎn)換

轉(zhuǎn)換前

class Person {
    // 公有屬性
    sex = '中性'
    // 私有屬性
    #height = 160

    // constructor 構(gòu)造函數(shù) 一個類只能有一個
    // 一個構(gòu)造函數(shù)可以使用 super 關鍵字來調(diào)用一個父類的構(gòu)造函數(shù)。
    constructor(name, age, height) {
        this.name = name
        this.age = age
        this.#height = height
    }

    // Getter
    get info() {
        console.log('name: ' + this.name + '-- age: ' + this.age)
    }

    // Methods
    log() {
        console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + this.#height)
    }

    // static
    // 靜態(tài)方法 作用于類本身
    // 只有類本身才能調(diào)用
    static getName() {
        console.log(this.name)
    }

    static a = 1
}

class Man extends Person {
    // 子類中定義了構(gòu)造函數(shù),那么它必須先調(diào)用 super() 才能使用 this 
    constructor(name, age, height, sex) {
        super(name, age, height)
        this.sex = sex
    }

    log() {
        //+ '-- #height: ' + this.#height
        // #height 私有的在這里拿不到
        console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex)
    }
}

const man = new Man('Joe', 10, 90, '男')

轉(zhuǎn)換后

// 全都運行在嚴格模式下
"use strict";

function _typeof(obj) {
    "@babel/helpers - typeof";
    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
        _typeof = function _typeof(obj) {
            return typeof obj;
        };
    } else {
        _typeof = function _typeof(obj) {
            return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
        };
    }
    return _typeof(obj);
}

function _inherits(subClass, superClass) {
    // 超類必須是 funciont or null
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
    }
    // 繼承
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            writable: true,
            configurable: true
        }
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
    // 動態(tài)這是原型對象的指向
    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
        o.__proto__ = p;
        return o;
    };
    return _setPrototypeOf(o, p);
}

function _createSuper(Derived) {
    return function () {
        // 拿到超類
        var Super = _getPrototypeOf(Derived), result;
        if (_isNativeReflectConstruct()) {
            var NewTarget = _getPrototypeOf(this).constructor;
            result = Reflect.construct(Super, arguments, NewTarget);
        } else {
            // 通過 apply 的方式
            // 繼承成員屬性
            result = Super.apply(this, arguments);
        }
        // 返回當前子類的實例
        return _possibleConstructorReturn(this, result);
    };
}

function _possibleConstructorReturn(self, call) {
    if (call && (_typeof(call) === "object" || typeof call === "function")) {
        return call;
    }
    return _assertThisInitialized(self);
}

function _assertThisInitialized(self) {
    // 還沒有被初始化- super()還沒有被調(diào)用
    // void 0 相當于 undefined
    if (self === void 0) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return self;
}

//  判斷是否支持 Refect or Proxy
function _isNativeReflectConstruct() {
    // Reflect 是一個內(nèi)置的對象,它提供攔截 JavaScript 操作的方法。這些方法與proxy handlers的方法相同。Reflect不是一個函數(shù)對象,因此它是不可構(gòu)造的。
    // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

    // 判斷 Reflect 是否存在
    if (typeof Reflect === "undefined" || !Reflect.construct) return false;
    // sham 屬性暫不知道有啥用
    if (Reflect.construct.sham) return false;
    if (typeof Proxy === "function") return true;
    try {
        Date.prototype.toString.call(Reflect.construct(Date, [], function () {
        }));
        return true;
    } catch (e) {
        return false;
    }
}

function _getPrototypeOf(o) {
    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _getPrototypeOf(o);
}

// 判斷當前 this 是不是 構(gòu)造函數(shù)的實例
function _instanceof(left, right) {
    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
        return !!right[Symbol.hasInstance](left);
    } else {
        return left instanceof right;
    }
}

// 不能已函數(shù)的形式調(diào)用類
function _classCallCheck(instance, Constructor) {
    if (!_instanceof(instance, Constructor)) {
        // 終止程序
        throw new TypeError("Cannot call a class as a 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);
    }
}

function _createClass(Constructor, protoProps, staticProps) {
    // 給原型添加方法
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    // 添加靜態(tài)方法
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
}

function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
    } else {
        obj[key] = value;
    }
    return obj;
}

function _classPrivateFieldGet(receiver, privateMap) {
    var descriptor = privateMap.get(receiver);
    if (!descriptor) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}

function _classPrivateFieldSet(receiver, privateMap, value) {
    var descriptor = privateMap.get(receiver);
    if (!descriptor) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        // 試圖設置只讀私有字段
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
    return value;
}

var Person = /*#__PURE__*/function () {
    // 構(gòu)造函數(shù)
    function Person(name, age, height) {
        // 判斷構(gòu)造函數(shù)的調(diào)用方式
        _classCallCheck(this, Person);

        // 給當前實例添加 sex 屬性
        _defineProperty(this, "sex", '中性');

        // 私有屬性
        _height.set(this, {
            writable: true,
            value: 160
        });

        // 添加成員屬性
        this.name = name;
        this.age = age;

        // 設置私有屬性
        _classPrivateFieldSet(this, _height, height);
    }


    _createClass(Person, [{ // 原型上的方法
        key: "log",
        value: function log() {
            console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex + '-- #height: ' + _classPrivateFieldGet(this, _height));
        }
    }, {
        key: "info",
        get: function get() {
            console.log('name: ' + this.name + '-- age: ' + this.age);
        }
    }], [{ // 靜態(tài)方法
        key: "getName",
        value: function getName() {
            console.log(this.name);
        }
    }]);

    return Person;
}();

// WeakMap 以對象做于 key ,值為任意類型
// 弱引用 不影響垃圾回收機制
var _height = new WeakMap();

// 靜態(tài)屬性
_defineProperty(Person, "a", 1);

var Man = /*#__PURE__*/function (_Person) {
    // 實現(xiàn)繼承 并 動態(tài)綁定構(gòu)造函數(shù)的原型對象
    _inherits(Man, _Person);

    // 創(chuàng)建一個獲取父類的方法
    // 返回一個函數(shù)
    var _super = _createSuper(Man);

    function Man(name, age, height, sex) {
        var _this;

        _classCallCheck(this, Man);

        // 調(diào)用父類的構(gòu)造函數(shù)
        _this = _super.call(this, name, age, height);
        _this.sex = sex;
        return _this;
    }

    _createClass(Man, [{
        key: "log",
        value: function log() {
            console.log('name: ' + this.name + '-- age: ' + this.age + '-- sex: ' + this.sex);
        }
    }]);

    return Man;
}(Person);

var man = new Man('Joe', 10, 90, '男');

// 動態(tài)的將 Man.__proto__ 指定成 Person
// 默認應該指向 Function.prototype
console.log(Man.__proto__ === Person) // true
console.log(Man.__proto__ === Function.prototype) // false

【筆記不易,如對您有幫助,請點贊,謝謝】

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容