当前位置: 首页 > 后端技术 > Node.js

Nodejs:ESModule和commonjs,傻傻的搞混了

时间:2023-04-03 17:08:49 Node.js

好久没更新博客了,最近写nodejs脚本的时候遇到了commonjs和ESModule的问题,之前只是亏本用着,学习一下这次。ESModuleexportsonlyexportnamedexports:namedexports,每次可以导出一个或多个。defaultexports:默认导出,一次只能存在一个。以上两种可以混合导出。//命名导出exportconstb='b'//默认导出exportdefault{a:1};constc='c'export{c}//将以上内容合并导出,即导出为:{b:'b',c:'c',default:{a:1}}Formore例子,可以直接上mdn。再导出(re-exporting/aggregating)是一种用于导入和导出的语法糖。export{defaultasfunction1,function2,}from'bar.js';//相当于import{defaultasfunction1,function2}from'bar.js';导出{函数1,函数2};但是,这个语法会报错:exportDefaultExportfrom'bar.js';//无效正确的语法应该是:export{defaultasDefaultExport}from'bar.js';//valid我猜是因为export本身支持的exportxxx的语法must是导出一个对象,但是importxxx可能是任何类型,两者冲突,所以最好不要让这个语法从编译级别。嵌入式脚本嵌入式脚本不能使用导出。引入语法importallexports:import*asallVar,所有导出内容,包括namedexport和defaultexport。allVar会是一个对象,默认export会是allVar的键名对应的值。导入命名导出:导入{var1,var2},导入命名导出。如果没有找到,对应的值是undefined。个人认为可以看作是“importallexports”的解构语法。importdefaultexports:importdefaultVar,导入默认导出的部分。importsideeffects:import"xxx./js",只运行这个js,大概是为了获取它的副作用。//test.jsexportconstb='b'//namedexportexportdefault{//defaultexporta:1};//index.jsimport{b,defaultas_defaultModule}from'./test.js'importdefaultModulefrom'./test.js'import*asallModulefrom'./test.js'console.log('nameexport',b)//'b'console.log('defaultexport',defaultModule)//{a:1}console.log(_defaultModule===defaultModule)//trueconsole.log('allexport',allModule)//{b:'b',default:{a:1}}旧记录错误大小写//test.jsexportdefault{//defaultexporta:1};//index.jsimport{a}from'./test.js'console.log('nameexport',a)//undefined//index.jsimportdefaultModulefrom'./test.js'import*asallModulefrom'./test.js'console.log('defaultexport',defaultModule)//{a:1}console.log('allexport',allModule)//{default:{a:1}}嵌入时脚本导入模块,需要在脚本中加入type="module"。livebindings的特性在mdn上通过export解释,export就是livebindings,再结合其他文章综合判断,应该是引用的意思。也就是什么export出口是引用。模块中的值更新后,所有使用export导出值的地方都可以使用最新的值。read-only在mdn上是通过import说明的,import使用的是通过export导出的不可修改的引用。严格模式引入的模块将在严格模式下运行。staticimport和dynamicimportimportxfrom的语法具有语法刚性,编译时需要放在最前面,不能动态导入加载。如果需要动态导入,则需要import()语法。有意思的是,在mdn上,前者归类为Statements&declarations,后者归类为Expressions&operators。这两者是根据什么分类的?true&&从“./a.js”导入测试;//SyntaxError:importcanonlybeusedinimport()orimport.meta//这应该是import被当成动态import时报错的例子//a.jsconsttest={a:1};导出默认测试;//更改模块内的值setTimeout(()=>{test.a=2;},1000);//index.js从'./index.js导入测试js'/*实时绑定*/console.log(test)//{a:1}setTimeout(()=>{console.log(test)//{a:2}},2000)/*只读*/test={a:3}//错误,错误:“test”是只读的。/*语法严格*/if(true){importtestfrom'./index.js'//错误,SyntaxError:'import'和'export'可能只出现在顶层}commonJSexports在Node.js模块中系统中,每个文件都被视为一个独立的模块。模块的导入导出实际上是由nodejs的模块包装器实现的,具体内容的导出是通过给module.exports赋一个新的值来实现的。module.exports有一个速记变量exports,其实就是一个引用拷贝。导出的范围仅限于模块文件的内部。原理类似://nodejsinternalexports=module.exportsconsole.log(exports,module.exports)//{},{}console.log(exports===module.exports)//true注意nodejs其实exports就是module.exports,我们分别来看下面几个经典案例:=xxxcase2://?这样写就可以导出了,最后导出的是{a:'1'}module.exports={a:'1'}console.log(exports,module.exports)//{},{a:'1'}console.log(exports===module.exports)//false//?不会导出{a:'1'},最后导出为{}exports={a:'1'}console.log(exports,module.exports)//{a:'1'},{}console.log(exports===module.exports)//false参考nodejs进阶视频讲解:进入通过require语法学习导入://a是test.js中module.exports导出的部分consta=require('./test.js')原理伪代码:functionrequire(/*...*/){const模块={出口:{}};((module,exports)=>{//模块代码在这里。在这个例子中,定义一个函数。functionsomeFunc(){}exports=someFunc;//此时,exports不再是module.exports的快捷方式,And//这个模块仍然会导出一个空的默认对象。模块。exports=someFunc;//此时,模块现在将导出someFunc,而不是//默认对象。})(模块,模块。导出);returnmodule.exports;}特征值复制//test.jslettest={a:'1'}setTimeout(()=>{test={a:'2'}},1000)module.exports=test//index.jsconsttest1=require('./test.js')console.log(test1)//{a:1}setTimeout(()=>{console.log(test1)//{a:1}},2000)ESModule和commonJS语法的区别exports、module.exports和require是Node.js模块系统的关键词。export、exportdefault、import是ES6模块系统的关键字:原理exports,module.exports导出的模块按值复制。export和exportdefault通过引用复制。ESModule静态加载的时机在编译时确定,ESModule动态加载的时机在运行时确定。CommonJS是运行时决定的。