require和import区别

272 阅读1分钟

使用场景不一样

require/exports是CommonJS规范,node环境使用,浏览器不支持,需要打包工具转

import/export是ES6规范,浏览器环境通过<script type='module'>使用,node中官方不建议使用。使用的话也是babel转成CommonJS

模块机制不一样

require是运行时加载,import是编译时输出接口。

commonJS模块

因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。--阮一峰

commonJS中,每个模块是一个对象,module变量表示对当前模块的引用。

module.exports是一个module对象的属性,表示当前模块对外输出的接口。把想要输出的对象指派给module.exports,其他文件加载该模块,实际上就是读取module.exports变量。

我们可以打印看一下module对象。

// module-a.js
let counter = 1
function incCounter(){
    counter++
}
module.exports = {
    getCounter: ()=>{
        return counter
    },
    incCounter: incCounter,
}
console.log(module)

$ node main-commonjs.js 
Module {
  id: '/Users/wangsisi/code/js-code/modules/module-a.js',
  path: '/Users/wangsisi/code/js-code/modules',
  exports: {
    getCounter: [Function: getCounter],
    incCounter: [Function: incCounter]
  },
  filename: '/Users/wangsisi/code/js-code/modules/module-a.js',
  loaded: false,
  children: [],
  paths: [
    '/Users/wangsisi/code/js-code/modules/node_modules',
    '/Users/wangsisi/code/js-code/node_modules',
    '/Users/wangsisi/code/node_modules',
    '/Users/wangsisi/node_modules',
    '/Users/node_modules',
    '/node_modules'
  ]
}

看一个例子

const path = './' + fileName;
const myModual = require(path);

上面的语句就是动态加载,require到底加载哪一个模块,只有运行时才知道。import语句做不到这一点。

ES6 模块

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。因为不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

// 报错'import' and 'export' may only appear at the top level 
if (x === 2) {
	import MyModual from './myModual';
}

引擎处理import语句是在编译时,这时不会去分析或执行if语句,所以import语句放在if代码块之中毫无意义,因此会报句法错误。

输出不一样

require输出的是值的拷贝

// module-a.js
let counter = 1
function incCounter(){
    counter++
}
module.exports = {
    counter: counter,
    incCounter: incCounter,
}
// main-commonjs.js
var mod = require('./module-a')
console.log(mod.counter);  
mod.incCounter();
console.log(mod.counter);
$ node main-commonjs.js 
1
1

修改一下,用一个函数去取counter

// module-a.js
let counter = 1
function incCounter(){
    counter++
}
module.exports = {
    getCounter: ()=>{
        return counter
    },
    incCounter: incCounter,
}
// main-commonjs.js
var mod = require('./module-a')
console.log(mod.getCounter());  
mod.incCounter();
console.log(mod.getCounter());
$ node main-commonjs.js 
1
2

import输出的是值的引用

ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。- 阮一峰

// 在node环境下执行import要设置成.mjs文件,并且用`node --experimental-modules`启动

// main-es6.mjs
import { counter,incCounter } from './module-b'
console.log(counter); //1
incCounter();
console.log(counter); //2

// module-b.mjs
export let counter = 1
export function incCounter(){
    counter++
}
$ node --experimental-modules main-es6.mjs
1
2

同步异步不一样

CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

import虽然写在文件顶部,但是脚本执行时,在碰到这个只读变量的时候,才执行被加载的模块。

参考

ES6 import()函数用法

require和import的区别

笔记:总结require和import的区别

彻底搞清楚javascript中的require、import和export

ES6 模块与 CommonJS 模块的差异 nodejs-module