最近在项目里面经常会看到require和import这两种引入依赖的方式,一直不太了解这两种引入方式的区别,趁着有时间,打算捋一捋,整理一下。
首先,我们要知道require和import本质上都是为了JS模块化编程使用的一个语法,语法一般都遵循这一定的语法规范,require遵循的是AMD/CommonJS规范,而import是es6新引入的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法。
有童鞋会问,AMD,CommonJS是个啥东东?下面我会简单的讲一下。
我们知道,任何语言都有它的语言规范,有了一个好的规范,才会有利于维护一个良好的语言生态。
AMD:即Asynchronous Module Definition,中文名是异步模块定义,一个在浏览器端模块化开发的规范,它完整描述了模块的定义,依赖关系,引用关系以及加载机制。
CommonJS:和AMD类似,它与AMD的区别是它加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
一, import和require的用法详解:
(1)import和require区别
require是赋值过程,其实require的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量
import是解构过程,但是目前所有的引擎都还没有实现import,我们在node中使用babel支持ES6,也仅仅是将ES6转码为ES5再执行,import语法会被转码为require
(2) import 使用示例
注:import是ES6的语法,有些地方不支持,可能报以下的错误
解决方法如下:
用babel来将import转换为es5语法。
安装:
npm install --save-dev babel-preset-env babel-cli
新建.babelrc文件
{ "presets": ["env"] }
执行
babel-node xxx.js
嗯~以为完美解决了,运行了之后又报了错
查了一波资料,说是我的babel没有全局引用的原因,不太想直接全局引用,所以用package-json配置进来,配置如下:
{
"name": "demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": {
"runImport": "babel-node import.js", "runR": "babel-node require.js" }, "author": "tanla"}
再运行,嗯~正常了
接下来讲一下impor引入和require引入,首先是import引入方式,代码如下:
import.js
import {a,c} from './a'; import * as lib from './a';console.log(a());console.log(lib.a());console.log(c);console.log(lib.c);
a.js
export function a(){
let a = 10; let b = 20; return a + b;}export let c = 40
运行结果
30304040
可以看到import引入有两种方式:一种是按需引入,引入当前所需要的方法和变量,一直是全部引入,可以用as重命名一下。其实import还可以为模块指定默认输出(export default),使用方式如下:
import-default.js
export default function () {
console.log('foo'); }
import.js
import defaultI from './import-default'defaultI();
输出
foo
好吧,讲一下这两个的区别和应用场景吧
import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(a.js
)对外接口的名称相同。可以看到我上面要引入export中的变量和方法时,都是要在大括号里面指定一样的变量名,否则就会报错。
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名。
这样的话export就要求我们清楚的知道引入的模块里的属性和方法,可是在实际开发过程中,我们未必有那么多时间去阅读文档来了解每个模块,所以我们需要export-default命令,我们可以看到我们引入的时候,并没有指定引入模块的方法和变量,我们可以随意命名,一个模块只能使用一次export-default命令,所以这个时候也不用加大括号。export default
命令其实只是输出一个叫做default
的变量。接下来,我进行了一个这样的操作
import.js
import defaultI from './import-default'console.log(defaultI());
输出
fooundefined
当我试着把这个dedault对象打印出来的时候,我发现输出undefined,很疑惑,这一点没有很明白。猜测估计是和这个对象有关。
接下来是require引入方式
require.js
const a = require('./b');console.log(a.c(2,4));
b.js
let f = function a(a,b){
return a+b;}let e = function ee(a,b){
return a-b;}exports.c = e;module.exports.c = f;
输出
6
好吧,又看到了两个不一样导出模版的方式module.exports
和exports
我们知道module和exports是Node.js给每个js文件内置的两个对象,可以打印出来看到,一开始,他们都是{},并且他们指向的是同一块内存,所以不去改变他们指向的内存地址的话,其实他们是等价的。所以我们可以试一下,将上面b.js中的7行和8行替换一下位置,下面输出的是-2。require引入的对象本质上是module.exports。但是因为export和他指向的是同一块内存,所以当export将其里面的值修改了之后,require获取到的值也会发生变化。接下来,可以看一下下面这波操作
c.js
module.exports = {name: 'uuuu'};exports = {name: 'yyy'};
require.js
const c = require('./c');console.log(c);
输出
{ name: 'uuuu' }
这时,module.exports指向的是一块新的内存{name: 'uuuu'},而exports也指向一个新的内存{name: 'yyy'},require获取的是module.exports的值,所以,module.exports和exports的赋值顺序就不会影响到它的引入了。