js中关于require与import的区别及说明
作者:bye_cherry
require和import的区别
起源
es6诞生之前,js一直没有模块系统,就连css都有@import,对现在复杂的大型项目开发无疑是一种阻碍。
es6在2015年6月正式发布,所以es6也有一个别称es2015。官方没有提出es6之前,社区给出了解决模块问题的方案,那就是node.js。
介绍到这个地方,其实require和import的起源已经出现了,es6中模块解决方案使用的关键字是import,而node.js提供的解决方案使用的关键字是require。
node.js由Ryan Dahl在2009年发布。node.js提供的模块化也叫CommonJS,不过node.js主要用于服务端的开发,但是随着时代的发展,现在的一些前端框架也依赖node.js
导出命令/引入命令
要想使用require或者import,首先得知道使用这两种方式对应的导出方式是怎样的,从现在开始,下文分别以CommonJS和es6来区分两种解决方案。
CommonJS
导出变量,方法,对象
// testcommonjs.js exports.a = 123; exports.b = 'hello'; exports.c = function(){ console.log('ccc') } exports.d = { foo: 'bar' } //等价=> module.exports.a = 123; module.exports.b = 'hello'; //等价=> module.exports = { a:123, b:'hello', c:function(){ console.log('ccc') }, d:{ foo:bar } }
建议使用module.exports,单独使用exports在某些情况下会产生意想不到的错误,这不是本文讨论的重点
引入和使用
//index.js var test = require('./testcommonjs') console.log(test.a) console.log(test.b) test.c() console.log(test.d.foo)
es6
导出变量,方法,对象(这里只列举常用的一些方法,具体的使用方法请参考阮一峰es6入门)
//testesmodule.js export var a = 123 export var b = 'hello' export function c(){ console.log('ccc') } export var d = { foo: 'bar' }
引入和使用
import { a,b,c,d } from './testesmodule' console.log(a) console.log(b) c() console.log(d.foo) //等价=> import * as test form './testesmodule' console.log(test.a) console.log(test.b) test.c() console.log(test.d.foo)
静态优化
这是从阮一峰大神的文档中学习到的一个概念。他在文档中以node的核心模块fs举了一个例子
es6
// ES6模块 import { stat, exists, readFile } from 'fs';
注:不要试图在没有配置babel的项目中去测试上面的代码,因为node到目前为止依然不支持es6的模块化语法(笔者目前的node版本:v10.15.0),尽管它已经实现了绝大部分的es6特性。
CommonJS
// CommonJS模块 let { stat, exists, readFile } = require('fs');
这样看起来,fs模块的引入方式在es6中和CommonJS中似乎只是语法上的区别,但是实际上,在CommonJS中上述代码的处理方式是这样的
let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;
也就是说,为了使用fs中的stat、exists、readFile方法,在代码执行使必须把fs整个模块全部加载进来,生成一个对象_fs,然后再从这个对象上面读取3个方法,这种加载被称为“运行时加载”,因为只有运行时才能得到这个对象。
而es6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量,从这个角度上来看,es6的模块化效率要比CommonJS高得多。阮一峰大神在文档中还列举了一些静态加载的其他优点,但是本菜鸟并不能看懂╮(╯▽╰)╭
新的思考:
fs是node.js的核心模块,为什么es6的模块化语法能够生效,在ws中通过文件定位,发现node.js的核心模块代码全是用ts写的,但是由于对ts语法不太熟悉,无法理解ts是如何能够做到既兼容CommonJS又兼容es6的。
(com)require和import,动态和静态
require和import的区别问题
require用于读取并执行js文件, 并返回该模块的exports对象, 若无指定模块, 会报错。CommonJS规范加载模块是同步且动态的, 只有加载完成, 才能执行后续操作。可以在代码中引入
import用于引入外部模块, 其他脚本等的函数, 对象或者基本类型。
import属于ES6的命令, 它和require不一样, 它会生成外部模块的引用而不是加载模块,等到真正使用到该模块的时候才会去加载模块中的值。
动态引入和静态引入
webpack支持node的commonJS标准,而且它的require实现和node极为类似;所以将node的require和webpack的require放在一起讲:
而且因为vue用了webpack,所以在vue中webpack的require也可以使用;
require是动态引入,因为他是运行时调用,可以放在代码的任何位置。
使用webpack的require需注意:
let url = "@/assets/images/carousel/logo.svg" require(url) //报错 let url = "logo.svg" require("@/assets/images/carousel/"+url); //正确
不能直接给require变量,要给require一个初始的地址,具体的文件名给变量,以方便遍历
而import支持静态引入和动态引入两种:
1.静态引入
import { a, b, c } from "./a";
2.动态引入
if (condition) { import('moduleA').then(...); } else { import('moduleB').then(...); }
PS1:区分静态和动态
静态是按照文件的嵌套关系找到文件或者分析代码,不需要运行
动态与执行顺序有关,会在执行的过程中根据变化进行一些操作
PS2:node中两种导出方式的区别
1.置换exports整个对象
module.exports = {} const lib = require("xxx")
2.不置换,只是编辑exports,加属性,这个aaa就是key
exports.aaa === module.exports.aaa exports.aaa = 123 const {aaa} = require("xxx")
无论时哪种,最后返回的都是exports对象,都可以通过键值从里边拿值
PS3:ES6中两种导出方式的区别
1.export
export func1=()=>{} export func2=()=>{} import { func1, func2 } from 'xxx';
2.export default
export default class Example{} import Example from "xxx"
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。