在 es6 之前 JS 一直没有自己的模块语法,为了解决这种尴尬就有了require.js等AMD或CMD方式的出现。在 es6 发布之后 JS 又引入了 import 的概念使得不清楚两者之间的区别的同学在实际使用过程中造成了自己的误解,在查阅了相关资料之后在此记录下自己的小小见解。
一、require 与 import 基本用法及引入方式区别
1、require的基本语法
核心概念:在导出的文件中定义 module.export,导出的对象的类型不予限定(可以是任何类型,字符串,变量,对象,方法),在引入的文件中调用 require() 方法引入对象即可。
//a.js中 module.export = { a: function(){ console.log(666) } } //b.js中 var obj = require('../a.js') obj.a() //666
本质上是将要导出的对象赋值给module这个的对象的export属性,在其他文件中通过require这个方法访问该属性
require 的使用非常简单,它相当于module.exports的传送门,module.exports后面的内容是什么,require的结果就是什么,对象、数字、字符串、函数……再把require的结果赋值给某个变量,相当于把require和module.exports进行平行空间的位置重叠
require('./a')(); // a模块是一个函数,立即执行a模块函数 var data = require('./a').data; // a模块导出的是一个对象 var a = require('./a')[0]; // a模块导出的是一个数组
2、import的基本语法
核心概念:导出的对象必须与模块中的值一一对应,换一种说法就是导出的对象与整个模块进行解构赋值。抓住重点,解构赋值!
//a.js中 // 最常使用的方法,加入default关键字代表在import时可以使用任意变量名且不需要花括号{} export default { a: function(){ console.log(666) } } export function(){ //导出函数 } export {newA as a ,b,c} // 解构赋值语法(as关键字在这里表示将newA作为a的数据接口暴露给外部,外部不能直接访问a) //b.js中 import a from '...' //import常用语法(需要export中带有default关键字)可以任意指定import的名称 import {...} from '...' // 基本方式,导入的对象需要与export对象进行解构赋值。 import a as biu from '...' //使用as关键字,表示将a代表biu引入(当变量名称有冲突时可以使用这种方式解决冲突) import {a as biubiubiu,b,c} //as关键字的其他使用方法
二、require 与 import 主要区别
1、区别1:模块加载的时间
require:运行时加载 —— require 是赋值过程,且是运行时才执行
import:编译时加载(效率更高)—— import 是解构过程,且是编译时执行
由于是编译时加载,所以 import 命令会提升到整个模块的头部,下面代码不会报错,正常执行
test(); import { test} from '/test';
2、区别2:对性能的影响
require的性能相对于import稍低:因为 require 是在运行时才引入模块,并且还赋值给某个变量;
而 import 只需要依据 import 中的接口在编译时引入指定模块,所以性能稍高。
3、区别3:模块的本质
require:模块就是对象,输入时必须查找对象属性
import:ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令输入(这也导致了没法引用 ES6 模块本身,因为它不是对象)。由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。
// CommonJS模块 let { exists, readFile } = require('fs'); // 等同于 let fs = require('fs'); let exists = fs.exists; let readfile = fs.readfile;
上面CommonJs模块中,实质上整体加载了fs对象(fs模块),然后再从fs对象上读取方法
// ES6模块 import { exists, readFile } from 'fs';
上面ES6模块,实质上从fs模块加载2个对应的方法,其他方法不加载
4、区别4:严格模式
CommonJs模块和ES6模块的区别:
(1)CommonJs模块默认采用非严格模式
(2)ES6 的模块自动采用严格模式,不管你有没有在模块头部加上 “use strict”;
(3)CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用,举例如下
// m1.js export var foo = 'bar'; setTimeout(() => foo = 'baz', 500); // m2.js import {foo} from './m1.js'; console.log(foo); //bar setTimeout(() => console.log(foo), 500); //baz
在 commom.js 中 module.export 之后导出的值就不能再变化,但是在 es6 的 export 中是可以的。
var a = 6 export default {a} a = 7 //在es6中的export可以 var a = 6 module.export = a a = 7 //在common.js中,这样是错误的