class

作者: 欢西西西 | 来源:发表于2023-03-23 17:32 被阅读0次

function _typeof(obj) {
    "@babel/helpers - typeof";
    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator
        ? function (obj) { return typeof obj; }
        : function (obj) {
            return obj && "function" == typeof Symbol
                && obj.constructor === Symbol &&
                obj !== Symbol.prototype ? "symbol" : typeof obj;
        }, _typeof(obj);
}
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, _toPropertyKey(descriptor.key), descriptor);
    }
}
function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    Object.defineProperty(Constructor, "prototype", { writable: false });
    return Constructor;
}
function _toPropertyKey(arg) {
    var key = _toPrimitive(arg, "string");
    return _typeof(key) === "symbol" ? key : String(key);
}
function _toPrimitive(input, hint) {
    if (_typeof(input) !== "object" || input === null)
        return input;
    var prim = input[Symbol.toPrimitive];
    if (prim !== undefined) {
        var res = prim.call(input, hint || "default");
        if (_typeof(res) !== "object")
            return res;
        throw new TypeError("@@toPrimitive must return a primitive value.");
    }
    return (hint === "string" ? String : Number)(input);
}
function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
    /**
     * 因为class声明的类只能使用new来调用,否则会报错   
     * 表示这个构造函数不应该被当做普通函数调用
     * 其实这里没有做到识别new,如果更改this指向就能绕过这个校验:var p = new Person(); Person.call(p);
     * 
     * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target
     * 而使用new.target可以检测一个函数是否是作为构造函数通过new被调用的
     * function Test(){ console.log('谁调用呢,嗯?', new.target); }
     */
}

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

var Person = /*#__PURE__*/_createClass(function Person() {
    _classCallCheck(this, Person);
});


// #region ES5
function Person() { }


// 编译结果
function _Person() {
    _classCallCheck(this, _Person);
}
var Person = /*#__PURE__*/_createClass(_Person);

// Marks a function call as pure. That means, it can safely be dropped.
// 是可以告诉 webpack 一个函数调用是无副作用的
// 如果一个没被使用的变量定义的初始值被认为是无副作用的(pure),它会被标记为死代码,可以被安全删除
// https://www.webpackjs.com/guides/tree-shaking/#root

// #endregion

// #region 增加实例属性和原型方法
// class Company {
//     address = 'hangzhou';
//     constructor(name) {
//         this.name = name;
//         this._init();
//     }
//     _init() { }
//     getDisplayAddress() {
//         return `${this.name}:${this.address}`;
//     }
// }

// ES5
function Company(name) {
    this.address = 'hangzhou';
    this.name = name;
    this._init();
}
Company.prototype = {
    constructor: Company,
    _init: function () { },
    getDisplayAddress: function () {
        return `${this.name}:${this.address}`;
    }
};


// 编译后
var Company = /*#__PURE__*/function () {
    function Company(name) {
        _classCallCheck(this, Company);
        _defineProperty(this, "address", 'hangzhou');
        this.name = name;
        this._init();
    }
    _createClass(Company, [{
        key: "_init",
        value: function _init() { }
    }, {
        key: "getDisplayAddress",
        value: function getDisplayAddress() {
            return "".concat(this.name, "\uFF1A").concat(this.address);
        }
    }]);
    return Company;
}();
// #endregion

// #region 增加静态属性和静态方法

// class Company {
//     static address = 'hangzhou'
//     static getDisplayAddress() {
//         return `${this.name}:${this.address}`; // Company.getDisplayAddress()
//     }
// }

// 使用static修饰,使属性和方法挂在构造函数对象上
// 例如jQuery.ajax, ajax就挂在jQuery这个构造函数上,而不在它的prototype上,所以jQuery实例也不会访问到ajax方法
// Promise.all 和 Promise.prototype.then
// Vue.version挂在Vue这个构造函数上

// 编译后
var Company = /*#__PURE__*/function () {
    function Company() {
        _classCallCheck(this, Company);
    }
    _createClass(Company, null, [{
        key: "getDisplayAddress",
        value: function getDisplayAddress() {
            return "".concat(this.name, "\uFF1A").concat(this.address);
        }
    }]);
    return Company;
}();
_defineProperty(Company, "address", 'hangzhou');

// #endregion

// #region 增加私有属性和方法

// 【1】声明时使用下划线

// 【2】使用Symbol定义私有属性
// Object.getOwnPropertySymbols()获取

// 【3】哈希前缀 #
// MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_class_fields
// 浏览器兼容性:https://caniuse.com/?search=Private%20class%20fields
// static 和 非static 的区别是:定义在prototype上还是类本身上
// # 和 非# 的区别是:实例是否可以访问

// class Company {
//     #privateField;
// 
//     constructor() {
//         console.log(this.#privateField);
//         this.#init();
//     }
//     #init() {
//         this.#privateField = '仅内部使用'; 
//     }
// }

// babel的思路
// ——通过生成外部的属性和方法
var _privateField;
function _init() {
    _privateField = '仅内部使用';
}

function Company() {
    console.log(_privateField);
    _init.call(this);
}

// 多个实例,就需要保存多个_privateField


function _classPrivateMethodInitSpec(obj, privateSet) {
    _checkPrivateRedeclaration(obj, privateSet);
    privateSet.add(obj);
}
function _classPrivateFieldInitSpec(obj, privateMap, value) {
    // 在privateMap中存实例和该属性的映射关系
    _checkPrivateRedeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _checkPrivateRedeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _classPrivateMethodGet(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _classPrivateFieldSet(receiver, privateMap, value) {
    var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); // 获取descriptor
    _classApplyDescriptorSet(receiver, descriptor, value); // 设置value
    return value;
}
function _classExtractFieldDescriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _classPrivateFieldGet(receiver, privateMap) {
    var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); // 获取descriptor
    return _classApplyDescriptorGet(receiver, descriptor);
}
function _classApplyDescriptorGet(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _classApplyDescriptorSet(receiver, descriptor, value) {
    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;
    }
}

var _privateField = /*#__PURE__*/new WeakMap();
var _init = /*#__PURE__*/new WeakSet();
var Company = /*#__PURE__*/_createClass(function Company() {
    _classCallCheck(this, Company);

    _classPrivateMethodInitSpec(this, _init); // 把这个实例添加到_init里面
    _classPrivateFieldInitSpec(this, _privateField, { // 【初始化】:在WeakMap中设置{[this]: config}
        writable: true,
        value: void 0
    });

    console.log(_classPrivateFieldGet(this, _privateField)); // 【访问】
    _classPrivateMethodGet(this, _init, _init2).call(this); // 访问私有方法:调用_init2
});

function _init2() {
    _classPrivateFieldSet(this, _privateField, '仅内部使用'); // 【修改】
}

// #endregion

// 1. 原型方法和静态方法的区别
// 2. 检查构造函数是否是由new调用的
// 3. 实现私有属性的方法的方式

相关文章

网友评论

      本文标题:class

      本文链接:https://www.haomeiwen.com/subject/sbiirdtx.html