你还没掌握 js class 吗,试试这篇 es5 重写 class

139 阅读2分钟

class 的特点

  1. class 不能提升
  2. class 只能通过 new 实例
  3. class 采用的严格模式
  4. class的原型属性不能被遍历

class 例子

es6使用例子

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    say() {
        console.log('hello')
    }
    sayHi() {
        console.log('hi')
    }
    static cat() {
        console.log('eat')
    }
}

使用es5 模拟一个类

function Person(name, age) {
    // 特点3、使用严格模式
    'use strict'
    // check方法如下,用于检查是否通过 new 方式进行
    check();
    this.name = name;
    this.age = age;
}

检查是否通过 new 的方式进行

function check(instance, constructor) {
    // 特点2、class 只能通过 new 实例
    if(typeof new target === undefined){
        throw new Error('不是通过new执行')
    }
}

模拟一个class属性,如上面的例子中, 可以如下表示:

createClass(
    Person,
    // 实例props
    [
        {
            key: "say",
            value: function() {
                console.log('hello')
            }
        },
        {
            key: "sayHi",
            value: function() {
                console.log('hi')
            }
        }
    ],
    // 静态props
    [
        {
            key: "cat",
            value: function() {
                console.log('cat')
            }
        }
    ]
)

由上面描写这个createClass

// 
function createClass(constructor, props, staticProps) {
    function defineProps(target, props) {
        props.forEach(prop => {
            // 特点4、不能被遍历
            prop.enumerable = prop.enumerable || false;
            // 可以被删除
            prop.configurable = prop.configurable || true;
            // 通过Object.definedProperty实现
            Object.definedProperty(target, prop.key, prop);
        })
    }
    // 实例方法
    if(props && props.length) defineProps(constructor.prototype, props);
    // 静态方法
    if(staticProps && staticProps.length) defineProps(constructor, staticProps);
}

本质上来说,静态方法是给class本身赋值,实例方法相当于给实例赋值,实例就是Person.prototype

实现extends

假设有父类Animal,我们看看有些extends干了些啥,Person会继承Animal静态方法、属性、实例方法属性

function _extends(constructor, parentConstructor) {
    function extendStatics() {
        // 兼容老版本浏览器, 支持__proto__直接返回
        if({__prop__: []} instanceof Array){
            constructor.__proto__ = parentConstructor
            return 
        }
        for(var key in parentConstructor){
            // 如果constructor 不包含parentConstructor 的属性,就增加parentConstructor的属性在如果constructor上
            if(!(constructor.hasOwnProprety(key))){
                constructor[key] = parentConstructor[key]
            }
        }
    }
    // 继承静态属性和方法
    extendStatics();
    // 新的构造函数,将 constructor 只向
    function _newConstructor() {
        this.constructor = constructor;
    }
    // 如果父类是null, 则相当于创建一个新的对象
    if(parentConstructor === null) {
        constructor.prototype = Object.create(null);
    }else {
        // 否则,通过原型继承  _newConstructor.prototype 指向parentConstructor
        _newConstructor.prototype === parentConstructor.prototype;
        new _newConstructor();
    }
}
// exmpale _extends(Person, Animal)

总结

重写class源码后,有点茅塞顿开的感觉