博主的桌面工具软件已经正式开发,获取方式:
可以关注我的小程序【中二少年工具箱】获取。(若小程序更新有延迟,或关注小程序后续功能,可先收藏小程序)
通过下载链接
百度网盘:
链接:https://pan.baidu.com/s/15zDnSoEzJGSZLjpD2FYrMw?pwd=1234 提取码:1234 复制这段内容后打开百度网盘手机App,操作更方便哦
具体已实现功能,参考文章中二少年工具箱简介
本文主要解释前端两种模块化语法:es6模块化与commonjs模块化,纯前端一般遵循es6模块化,使用import语法导入插件,nodejs遵循commonjs模块化,使用require导入插件。
本文虽长,但读完后,正常情况下,足以应付大部分导入导出场景,使用其他人插件再也不用因为导入导出的语法耗费时间。
我的小程序后端采用midwayjs框架(nestjs也不错,个人项目支持一波国产),后端部署到腾讯云上,考虑到个人项目服务器有很大概率会迁移,下一个服务器什么情况不好预估,开发某些功能时就需要考虑时区问题,所以使用插件moment-timezone。
使用插件时,遇到报错,信息如下:Module ‘“F:/myProject/lize-tools-back/node_modules/moment-timezone/index”’ can only be default-imported using the ‘esModuleInterop’ flag
造成这报错的起因是我在导入插件时,使用了es6的默认导入方法,而moment-timezone插件遵循commonjs模块化。插件的源码就不贴了,因为它用了ts导出单个对象的方式,这部分知识点和我们本章要了解的并不想关,我们只需要知道,插件最终会被编译成
module.exports = moment
这是明显的commonjs导出方法。
而我如果使用es6默认导入方法:
import moment from 'moment-timezone'
就会报上面的错。
这错误并不是es6或者nodejs抛出的,因为从Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持(这句话抄的阮一峰大神,我没有自己考证)。
上面的错误其实是ts提示的,ts认为commonjs中没有默认导出的概念,默认导出是es6中的概念,所以自然也不能用import默认导入的方式。按照提示配置esModuleInterop,我们可以绕过报错,但是从这个报错,我正好整理了一下es6模块化和commonjs模块化(nodejs)导入导出的概念,希望对其他人有所帮助。
对于两种模块化的基础使用方式容易混淆,无非是没有认认真真地对比过它们,大家不愿意做,我来为大家节省时间:
导出语法 | 导入语法 | |
---|---|---|
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 |
其中xxx可以是函数、变量、类等任意对象。
简单举例:
module.exports={
test:'1'
}
exports.test=1
当然实际情况可能还有很多变种语法,但是初学者只需理解这两个最根本的即可。
学知识就和练葵花宝典一样,要学最紧要的心法,切了最重要,至于用针还是用剑,那就是变招,终会根据喜好水到渠成。
上面两个导出的效果一样,最终都是会得到一个对象exports,exports对象里有个key是“test”,对应的value是1。
两种写法无非就是一个明确告诉你exports对象是module的一个元素,另一个简洁化,没有告诉你exports前面其实还有个module。
就像前端写全局变量,直接写a=1和写window.a=1,有区别吗?没区别!
当然这是为了方便大家记忆,实际上exports是一个指向module.exports的引用,这样说有点过于拗口,用代码描述,就是底层代码通过exports===module.exports创建了exports。
所以我们使用exports时,千万要写成exports.test=1的形式,如果写成exports=1,那么exports和module.exports之间的关系很可能就被你强行断开,导致出错。(当然我没这么二去试过)
我为什么在介绍commonjs导出后,不接着介绍commonjs对应的导入?因为能看这篇文章的,我相信一定是对导入导出语法有一点了解,但又不多,大家会对commonjs导入和导出混淆吗?不会,大家更容易混淆的是commonjs的导出与es6的导出。
简单例子:
export default function test(){
}
export default class{
}
export default 1
export const test=function(){}
export const test=class{
}
export const test=1
其实对照着看commonjs和es6导出,很容易分辨出来。它俩唯一容易混淆的地方就是都有export这几个字母而已,但是两者的export单词代表的含义却完全不同。
commonjs中的是exports,它是一个对象,是要导出去的对象,所以带着s很好理解,因为这个对象可能有很多属性。
es6中的是export,它是一个关键字,是类似于function 、class这种具有一定功能性的方法,它又不是单纯的对象。不要杠前端一切皆对象,我相信能杠这种话的人一定知道我说的单纯对象是什么意思。
聊到这就很清晰了,commonjs中导出的就是这个exports对象,es6中导出的是export后面的对象。至于细节,两者的对象都可以是什么,构造这个对象有没有更多的方式,能不能重命名等等等等,自己去看看文档就知道了,我不建议死记硬背。
理解了基础,其他的用的多了自然就知道了,用的不多,说明不那么重要。
再简单聊下es6导出的两种形式,我们只需要理解export default中的default才是要导出去的变量,把它后面的对象赋值给default,然后导出,就是默认导出方式。所以default后面一定是一个对象或对象的引用,而不是声明语句。
如果写成export default const test=1,这就直接给es6干懵圈了,它不知道该导出default还是导出test。但如果写成:
const test=1
export default test
就是可以的,因为导出的还是default,只不过把变量a的值赋值给default了。就是说你可以写let a=b=c=3,但你不能写let a=let b=let c=3。
同理,export 1也不行,因为export是关键字,它要导出一个变量,1不是变量,但是export test就可以,因为test是我们声明的一个变量,不论它是在export这句话里声明的,还是在之前声明的。
这里,我建议不要使用export default默认导出方式,我有很长一段时间就只用export const test=1这一种写法,覆盖百分之九十九的业务场景。export default个人理解其实更多是插件、基础组件等需要考虑的。进阶内容就不展开说了,这是另外的价钱。
本来打算一篇文章写完的,结果发现不管怎么压缩,都需要很长的篇幅,还是把导入导出分开阐述吧。感觉读完本文有所收获,请搜索博主下一篇关于导入import的讲解。