近期學習nodejs時,我發現很多網上比較commonjs和esmodule不一樣之處的文章都提到commonjs的導出是值拷貝,導出值改變不會致使導入值改變,esmodule的導出是導出引用地址,導出值改變則導入值同時改變。 真的是這樣嗎?因而我試了試,發現問題沒有那麼簡單。node
實驗的目錄環境以下webpack
src
commonjs
- index.js
- lib.js
esmodule
- index.js
- lib.js
複製代碼
執行環境是nodejs 12.10.0web
代碼用nodejs直接執行一次bash
用webpack打包後nodejs執行一次(webpack和nodejs執行結果一致,下文就不區分是哪一種執行結果了。)ide
其中nodejs 使用esmodule的命令 node --experimental-modules index.js
學習
webpack 打包命令 node --experimental-modules index.js
ui
// index.js
const { ss } = require('./lib');
const lib = require('./lib');
console.log('ss', ss);
console.log('lib', lib);
setTimeout(()=>{
console.log('ss', ss);
console.log('lib', lib);
},3000);
複製代碼
// lib.js
module.exports.ss = 'ss1';
setTimeout(()=>{
module.exports.ss = 'ss2';
console.log('module.exports', module.exports);
},2000);
複製代碼
執行結果
ss ss1
lib { ss: 'ss1' }
lib module.exports { ss: 'ss2' }
ss ss1
lib { ss: 'ss2' }
複製代碼
// webpack打包後的相關代碼
/******/ ({
/***/ "./index.js":
/***/ (function(module, exports, __webpack_require__) {
const { ss } = __webpack_require__(/*! ./lib */ "./lib.js");
const lib = __webpack_require__(/*! ./lib */ "./lib.js");
console.log('ss', ss);
console.log('lib', lib);
setTimeout(()=>{
console.log('ss', ss);
console.log('lib', lib);
},3000);
/***/ }),
/***/ "./lib.js":
/***/ (function(module, exports) {
module.exports.ss = 'ss1';
setTimeout(()=>{
module.exports.ss = 'ss2';
console.log('module.exports', module.exports);
},2000);
/***/ })
/******/ });
複製代碼
從執行結果能夠看出spa
const { ss } = require('./lib');
至關於 const { ss } = {ss:'ss1'};
解構賦值,至關於const ss = 'ss1';
因此導出對象修改ss不能使導入對象ss
也變成2。commonjs的導出是值拷貝這句話是錯誤的,commonjs導出的是module.exports,commonjs的導入就是變量賦值。當module.exports的值是字符串、數字等原始類型時,賦值是值拷貝纔會產生導出值改變不會致使導入值改變的現象。指針
彷佛話題到此爲止,可是我又產生了一個疑惑,爲何會有commonjs的導出是值拷貝這個提法呢?因而我又實驗了一下esmodule,發現了一些有趣的東西。code
// index.js
import {a} from './lib.js';
import b from './lib.js';
console.log('a',a);
console.log('b',b);
setTimeout(()=>{
console.log('a',a);
console.log('b',b);
}, 3000);
複製代碼
// lib.js
export let a = 1;
let b = 1;
export default b;
setTimeout(()=>{
a = 2;
b = 2;
console.log('a', a);
console.log('b', b);
}, 2000);
複製代碼
執行結果
a 1
b 1
lib a 2
lib b 2
a 2
b 1
複製代碼
// webpack 導出文件
/******/ ({
/***/ "./index.js":
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _lib_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib.js */ "./lib.js");
console.log('a',_lib_js__WEBPACK_IMPORTED_MODULE_0__["a"]);
console.log('b',_lib_js__WEBPACK_IMPORTED_MODULE_0__["default"]);
setTimeout(()=>{
console.log('a',_lib_js__WEBPACK_IMPORTED_MODULE_0__["a"]);
console.log('b',_lib_js__WEBPACK_IMPORTED_MODULE_0__["default"]);
}, 3000);
/***/ }),
/***/ "./lib.js":
/*! exports provided: a, default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return a; });
let a = 1;
let b = 1;
/* harmony default export */ __webpack_exports__["default"] = (b);
setTimeout(()=>{
a = 2;
b = 2;
console.log('lib a', a);
console.log('lib b', b);
}, 2000);
/***/ })
/******/ });
複製代碼
從執行結果能夠看出
commonjs導出的是module.exports,commonjs的導入就是變量賦值。當module.exports的值是字符串、數字等原始類型時,賦值是值拷貝纔會產生導出值改變不會致使導入值改變的現象。 esmodule中的導入值更像一個指針,導入導出值都指向同一個同一個內存地址,因此導入值會隨導出值變化而變化。