js基础:require和import到底有什么区别
require
require 是 commonjs 的语法。module.exports 导出一个对象或者基础值。
并且该对象会被缓存在 require.cache。下一次 require 时,会从缓存读取,不会重新执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let num = 1;
setTimeout(() => { num = 22; }, 200);
module.exports = num;
let obj = require('./module1.js'); console.log(obj); setTimeout(() => { console.log(obj); }, 2000);
|
**有一些文章说,commonjs 模块输出的,是值的拷贝,我是不同意的**,浅拷贝,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let obj = { a: 1 };
setTimeout(() => { obj.a = 22; }, 200);
module.exports = obj;
let obj = require('./module1.js'); console.log(obj); setTimeout(() => { console.log(obj); }, 2000);
|
如果真的是一份拷贝值,暴露的值即使是引用类型,也不应该会变。 浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let obj = { a: 1 };
module.exports = obj;
let obj = require('./module.js');
setTimeout(() => { delete require.cache[require.resolve('./module.js')]; let obj1 = require('../review/module.js'); console.log(obj === obj1, 'index'); }, 2000);
|
如果在外部改变 require 模块暴露的值,模块内是会生效的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| let obj = { a: 1 };
setTimeout(() => { console.log(obj, '100'); }, 100);
setTimeout(() => { obj.a = 22; }, 200);
module.exports = obj;
let obj = require('./module.js');
obj.b = 1;
setTimeout(() => { console.log(obj, 'index'); }, 2000);
|
我们只能说,commonjs 会输出初始执行的结果(不管有没有缓存。即使没缓存,再执行一遍模块,输出结果也是一样的)。如果输出的值包含了引用类型,那更改一样会生效。这是 js 本身的特性,和 commonjs 没什么关系。
除非重新调用 module.exports,去更新模块暴露的值,并且重新执行 require:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let obj = { a: 1 };
setTimeout(() => { obj.a = 22; module.exports = 2; }, 200); module.exports = obj;
let obj = require('./module1.js'); console.log(obj); setTimeout(() => { console.log(require('./module1.js')); }, 2000);
|
import
import 是 es6 的语法。当使用非 default 暴露时,被引用模块中改变暴露值,引用方可以获取到变化(动态输出绑定)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let num = 1; setTimeout(() => { num = 22; }, 200); export { num };
import { num } from './module.js';
console.log(num);
setTimeout(() => { console.log(num); }, 2000);
|
使用 default 暴露,行为和 commonjs 一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let num = 1;
setTimeout(() => { num = 2; }, 1000);
export default num; export { num };
import mod, { num } from './mod.js';
console.log(mod, num);
setTimeout(() => { console.log(mod, num); }, 2000);
|
export 语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新。
对于 CommonJS:
1 2 3 4 5 6 7 8 9 10 11
| module.exports = { value: 1 };
const module = require('./module'); console.log(module.value); module.value = 2;
const moduleAgain = require('./module'); console.log(moduleAgain.value);
|
这里,module 的导出是共享的引用,更改会影响其他地方。
对于 ES6 模块:
1 2 3 4 5 6 7 8 9 10 11
| export let value = 1;
import { value } from './module'; console.log(value); value = 2;
import { value } from './module'; console.log(value);
|
在 ES6 中,导出的值是按引用绑定的,但在导入处不能直接修改它的值。要想修改导出的变量,通常需要在原模块中提供一个函数来进行修改。
- CommonJS 和 ES6 模块 是两种不同的模块系统,前者是动态的,后者是静态的,前者常用于 Node.js,后者被现代前端开发广泛采用。
- 导出机制:CommonJS 允许导出对象的动态引用,ES6 模块更偏向于静态分析和编译期优化。
- 值传递和拷贝:两者都是通过引用导出,类似浅拷贝,但 ES6 模块在导入后不能直接修改导入值,CommonJS 可以直接修改对象。
-
版权声明: 本博客所有文章除特别声明外,均采用
CC BY 4.0 CN协议
许可协议。转载请注明出处!
Жизнь, как качели - то вверх, то вниз.