webpack源碼中一些精妙的方法總結

前言

過年這一段時間一直在研究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源碼的精妙方法內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: