(github)javascript
在有2個或2個以上的文件之間的相互依賴關係構成閉環的時候,有時會出現Can't read Property 'xxx' of undefined
或者(0,xxx) is not a function
這類的錯誤,好比:java
示例項目中的src/index.js引用src/a.js,而src/a.js中也引用了src/index.js
複製代碼
這就跟webpack打包後的代碼執行邏輯有關webpack
webpack的頭部啓動代碼中,經過閉包中的installedModules對象,將模塊名或者id做爲對象的key來緩存各個模塊的export的值,經過判斷installedModules上是否緩存了對應模塊的key來判斷是否已經加載了模塊git
// Check if module is in cache
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// Create a new module (and put it into the cache)
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
複製代碼
但存在一個問題:當模塊還處於第一次執行中的狀態時,若是碰到相互引用的狀況的話,webpack可能會認爲一個沒有徹底加載完成的模塊已經加載完了github
就拿export function.js中的代碼和export const _var.js中的代碼爲例:web
export function.js緩存
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._console = _console;// <- 📢注意這裏
var _a = __webpack_require__(2);
var _a2 = _interopRequireDefault(_a);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _console() {
console.log('this is index.js');
}
/***/ }),
複製代碼
export const _var.jsbash
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._console = undefined;// <- 📢注意這裏
var _a = __webpack_require__(2);
var _a2 = _interopRequireDefault(_a);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _console = exports._console = function _console() {
console.log('this is index.js');
};
/***/ }),
複製代碼
從上面兩段代碼的📢處代碼行能夠看到,使用賦值語句export的代碼打包後,對exports上的屬性的賦值將在import(也就是__webpack_require__)後,另外一種使用申明函數語句export的代碼打包後,對exports上的屬性的賦值將在import(也就是__webpack_require__)前。閉包
這點細微的區別在執行相互引用的代碼時會致使執行結果和你想的不同,試想一下如下的代碼執行過程:函數
export的方式會影響以上過程的五、6步驟