一、CommonJS和ES6的差异
在浏览器上使用的是ES6
的模块规范,在node
中使用的是CommonJS
规范。(现在也可以使用一些第三方包在node
中使用ES6
的模块规范)。
import
、import()
、export
、export default
属于ES6的模块规范。
exports
、module.exports
、module
、require
属于CommonJS规范。
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
二、CommonJS模块
const {run,eat} = require('./dog.js')
CommonJS
使用require
引入模块的方式是动态的,所谓动态就是上面代码在被执行的时候,才会引入dog.js
模块,而且引入的是完整的一个对象,并不只是run
和eat
两个方法。所以上面这段代码也可以和下面的代码等同。
const dog = require('./dog.js')
const run = dog.run
const eat = dog.eat
module
在CommonJS
中,一个文件就是一个模块
,module
就表示当前模块的引用(module是一个对象)。module
作为一个对象
自然也就有关于当前模块信息的属性
。常见的有:module.exports
、module.children
、module.parent
等等,这里只需要关注module.exports
就行。
module.exports
module.exports
也是一个对象,该对象由系统创建,在外部文件引入此模块时实际就是引入了exports
对象。一般我们都采用module.exports.xxx
的方式导出数据,也可以使用直接给exports
赋值的方式导出数据。
//导出dog.js
module.exports.eat = function(){}
//引入
const {eat} = require('./dog.js')
//直接赋值给exports进行导出
module.exports = function(){}
//引入
const eat = require('./dog.js')
exports
exports
是个值得注意的地方。它的使用方法和module.exports
是一样的,类似于module.exports
的快捷方式。非常要注意的是不要直接给exports
赋值,只能使用.
对exports
的属性进行赋值,如果使用=
直接给exports
赋值会导致数据不能导出。
//正确使用
exports.eat = function(){}//等同于module.exports.eat = funciton(){}
//无法导出
exports = 123
require()
require()
用于引入模块、JSON、本地文件,这里只对引入模块做说明。其参数可以是模块名,也可以是文件路径。如果直接使用模块名,则会在node_modules
中或者内置模块
中进行引入。如果引入的是模块,该方法的返回值就是module.exports
对象。
//导出方式
module.exports.eat = function(){}
//导入方式
const {eat} = require('./dog.js')
//导出方式
module.exports = function(){}
//导入方式
const eat = require('./dog.js')
三、ES6模块
import {run,eat} from './dog.js'
run();
ES6采用import
的方式引入模块,这种方式和CommonJS正好相反,它是静态的引入模块,即在代码编译的时候就已经把run
和eat
方法引入了。所以在效率上会比CommonJS的require
方法效率更高。
export
注意和CommonJS
中exports
进行区别,export
在ES6中是个关键字,exports
在CommonJS
中是一个对象或属性。也就是说exports
必须使用=
对自身的属性进行赋值,而export
则使用声明的方式导出变量。
//CommonJS
exports.eat = function (){}
//ES6
export function eat(){}
export
用于暴露模块对外的接口。这里需要注意export暴露的是变量而不是值
。注意这两者的区别,下面代码对变量和值进行了解释。
export语句必须出现在模块的顶层,如果出现在块作用域中会报错。
//报错,导出的是1,并非a,1是值,export不能直接导出值
const a = 1
export a
//正确,导出的是b
export const b =1
//正确,导出的是一个对象
export {a}
//报错
function run (){}
export run
//正确
export function run(){}
export {run}
import
import
是输入接口,用来引入外部模块暴露出来的变量
或者值
,接口是只读的不可以被改变,如果接口是对象则可以更改对象的属性,但是不建议这样做。所有输入进来的东西我们不应该去更改它的原始值。
如果是使用export
方式导出的变量就需要在import
关键字后面直接接收(import {run} from './dog.js'
),如果使用的是export default
方式导出的值则需要在import
关键字后面给值一个变量来接收(import 自定义变量名 from './dog.js'
)。
看到这里也许会感觉矛盾,上面说了
export
只暴露变量,为什么import
会接收值
呢?因为有export default
的存在,它的作用就是直接暴露值
。其本质上也是暴露名为default
的变量
,但是理解为暴露的是值
。
//dog.js
export function run(){}
//people.js
import {run} from 'dog.js'
//dog1.js
export default function (){}
//people1.js
import run from 'dog1.js'
export default
export default
用于直接导出值
,比如直接导出数值、字符串、对象、数组、方法等。在使用import
引入的时候,直接给导出的值
一个变量就行了。
//dog.js
export default 1
//people.js
import dog from 'dog.js'
console.log(dog) //1
import()
import()
和import
两者都是输入接口,区别在于前者是动态加载的,后者是静态加载的。即前者在代码执行到import()
的时候才接入外部模块,而import
在代码编译的时候就已经接入了。import()
返回了一个promise
,可以使用解构赋值
的方式获取暴露的变量。
// 报错
function a (){
import run from 'dog.js'
}
//正确
function b (){
import('dog.js').then( ({run,eat}) => {
console.log(run)
})
}
粗浅了解,如果有不对的,希望可以得到指正。谢谢啦!