博主的桌面工具软件已经正式开发,获取方式:
-
可以关注我的小程序【中二少年工具箱】获取。(若小程序更新有延迟,或关注小程序后续功能,可先收藏小程序)
-
通过下载链接
-
百度网盘: 链接:pan.baidu.com/s/15zDnSoEz... 提取码:1234 复制这段内容后打开百度网盘手机App,操作更方便哦
具体已实现功能,参考文章中二少年工具箱简介
@TOC
前言
前面文章已经讲解es6模块化和commonjs模块化的导出语法,博主一贯作风都是只讲干货,不抄文档,前端同学去看看,绝对会有感触。
当然讲干货意味着加入了自己的理解,如果有失偏颇,还请各位大佬在不吝指教的同时,又能保持风度。
不水文的原创真的是太难了,感觉文章不错的同学积极点赞收藏和私信加群,不要矜持,很多技能边界,聊着聊着就拓展了。
一、commonjs模块化的导入
下表是上篇文章做过的对比:
导出语法 | 导入语法 | |
---|---|---|
commonjs模块化 | 1. module.exports=xxx 2.exports.变量名=xxx | const xxx=require() |
es6模块化 | 1.export default xxx 2. export xxx | 1.import {xxx} from 2.import xxx from 3.import * as xxx from |
为什么我这里对于commonjs模块化的导入语法,只写了一种?那是因为我们初学只需要关注这一种语法,其它的都是变种。
类似于数学中某一章节的定理可能只有一个,但是推理可以有很多个。理解了定理,推理不需要死记硬背。
写个简单例子:
c
const test=require('test.js')
这句话的意思是,在test.js中导出了一个对象,我们在这里得到这个对象,并赋值给变量test。上一章节我们详细讲过,commonjs导入导出是运行时进行,得到的是真正的对象,即exports。
不论以哪种形式导出对象,得到的都是这一个exports对象,所以导入时,自然也就只有一种语法。
那么我们为什么常见下面的写法:
c
const {a,b}=require('test.js')
这不过是一种变种写法,将解构语法和导入语法合二为一。其实它等价于两句话:
c
const test=require('test.js')
const {a,b}=test
而对应的导入语法也就有两种:
c
module.exports={
a:'1',
b:'2'
}
//或者
exports.a='1'
exports.b='2'
这就显而易见了,导出的永远是exports对象,对象里可以有其它属性,得到的永远都是test变量,变量可以直接解构出属性a、b。
在commonjs导出中,module.exports优先级高于exports,但是两者导出结果一样。
二、es6模块化导入
es6的模块化导入就不同于commonjs导入那么省事了。它不同的写法并不是变种,而是针对不同的场景。
- import {xxx} from
c
import {xxx} from 'test.js'
这种写法是从test.js中导出命名导出的变量/函数,也就是说这种写法就对应着
c
const xxx=...
export xxx
//或者合并两句
export const xxx=...
- import xxx from
c
import xxx from 'test.js'
这种写法是导入test.js中的默认导出模块,也就是对应着
c
export default xxx
如果你认真看过上一篇文章,那么应该理解上面两句代码中的xxx含义不同,导出语法导出的变量是default,这句计算机语言如果翻译成人话,更清晰的表述应该是类似:导出一个变量default,并为它赋值为xxx。而导入中的xxx则是指向导出的default,和导出中的xxx没有直接关系,所以两种并不用同名。也就是上面两句代码等价于:
c
import test from 'test.js'
export default xxx
- import * as xxx from
这是一种整体导入的方式,就是不管导出了哪些变量,我都导入并且把它赋值给xxx,然后可以通过==xxx.变量名== 的方式获取其中的变量。
三、运行时与静态分析时
仔细对比两种导入语法,我们可以发现require导入更像是一个函数,而import xxx from则更像一种固定的语法。
require()确实是一个内置的函数,与console.log()、alert()、parseInt()等等函数并没有什么区别。所以require导入模块是发生在运行时,也就是代码运行到这了,就会调用这个函数。
而import from并不是函数,它是发生在静态分析时,也就是编译时。它的作用是在这个位置插了个标记,告诉node,你以后编译代码,操作文件时,记得把from后面那个文件里的xxx函数给写到这里。
也就是说import引入的模块生效时,是在项目代码真正运行的阶段,但是模块早在代码运行之前,就已经被node自动写到了这里。
import虽然和普通函数写在一起,但是它们并不是一类。import真正生效的时机是在代码运行之前的编译过程,而其他普通函数生效的时机就是代码运行的时候。
所以我们这样写就会报错:
c
for(let i=0;i<2;i++){
import xxx from 'test.js'
}
if(1==1){
import xxx from 'test.js'
}
因为不管是for还是if,都是代码运行时的语法,而import是编译时需要查找的标记,nodejs在查找组合各个文件时,它知道什么是if和for吗,不知道!在node眼里,所有的一切都是文本字符而已,它的任务也不是去运行什么,而是找到相应的export,把它写入到import的位置而已。
五、总结
我写的两篇导入导出,只是自己的一些粗浅理解,想要了解模块化的全貌,还是要学习官方文档。这里强烈推荐阮一峰大神的es6入门教程作为参考手册。