前言

过年这一段时间一直在研究webpack的源码,由于过年周围气氛比较欢快,心态有点飘导致没有沉下心来仔细研究其中的细节。经过反思之后,静心重新捋顺webpack的源码,这时发现不少巧妙的方法值得学习。这里我已经迫不及待的跟大家分享了,希望对大家平常开发过程中有所帮助。

精妙方法

缓存函数

这个方法最精妙的地方在于将执行结果缓存,减少函数的重复执行以达到提升性能的目的,对于执行越复杂越耗时的函数收益越大。但是,不适用于动态执行结果的函数

    const memoize = fn => {
        let cache = false;
        let result = undefined;
        return () => {
            if (cache) {
                return result;
            } else {
                result = fn();
                cache = true;
                fn = undefined;
                return result;
            }
        };
    };

这个方法跟惰性函数有点相似,只在函数第一次调用的时候执行,将fn()的执行结果缓存到result上,然后通过cache设置为true来标记缓存已开启。这里还有个细节值得学习:由于闭包的原因,fn方法被新的函数持有,一直在调用栈中得不到释放,而在代码中有一句fn = undefined,手动释放内存。

属性劫持

这个方法通过自定义get方法或者value值来重定义obj的属性。实现的结果有点类似于Object.freeze,但又不完全相同。通过Object.defineProperty定义name的get属性描述符来保证obj的值永远不变;通过Object.defineProperty来将name的writable设置为false来保证obj的value不会被改变。

    const mergeExports = (obj, exports) => {
        ...
        for (const name of Object.keys(descriptors)) {
            const descriptor = descriptors[name];
            if (descriptor.get) {
                const fn = descriptor.get;
                Object.defineProperty(obj, name, {
                    configurable: false,
                    enumerable: true,
                    get: memoize(fn)
                });
            } else if (typeof descriptor.value === "object") {
                Object.defineProperty(obj, name, {
                    configurable: false,
                    enumerable: true,
                    writable: false,
                    value: mergeExports({}, descriptor.value)
                });
            } else {
                ...
            }
        }
        return Object.freeze(obj);
    };

这里还有个小的知识点:通过将属性的configurable属性描述符设置为false来保证属性不可被删除

数组比较

进行两个数组是否相等的比较。想必大家都知道,如果使用==进行数组比较的话,是进行引用地址的比较,所以想要判断两个数组是没有方法进行直接比较的。而webpack源码中的这个方法给我提供了一种数组比较的方式。当然了,这个方法只适用于扁平化的一维基本类型数组,如果想要比较复杂的情况的话,需要在for循环的基础上稍加改造。

    exports.equals = (a, b) => {
        if (a.length !== b.length) return false;
        for (let i = 0; i < a.length; i++) {
            if (a[i] !== b[i]) return false;
        }
        return true;
    };

配置项校验

webpack中的实现的代码量比较多,我们就只说一下大体实现思路,通过定义需要校验的所有配置项的Schema校验规则。大体Schema格式如下:

    "Amd": {
        "description": "Set the value of `require.amd` and `define.amd`. Or disable AMD support.",
        "anyOf": [
            {
                "description": "You can pass `false` to disable AMD support.",
                "enum": [false]
            },
            {
                "description": "You can pass an object to set the value of `require.amd` and `define.amd`.",
                "type": "object"
            }
        ]
    },

其中key对应的是需要校验的配置项,value中的desciption对应的是提示信息,其余部分对应的是校验规则。

结尾

到此这篇关于webpack源码中一些精妙的方法的文章就介绍到这了,更多相关webpack源码的精妙方法内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部