近期学习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中的导入值更像一个指针,导入导出值都指向同一个同一个内存地址,因此导入值会随导出值变化而变化。