阅读 2809

js使用require 和 import 引入依赖的区别?

最近在项目里面经常会看到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) js使用环境搭建

注: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"
}
复制代码
(3) 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
复制代码

运行结果

30
30
40
40
复制代码

可以看到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());
复制代码

输出

foo
undefined
复制代码

当我试着把这个dedault对象打印出来的时候,我发现输出undefined,很疑惑,这一点没有很明白。猜测估计是和这个对象有关。

(4) 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的赋值顺序就不会影响到它的引入了。

文章分类
前端
文章标签