一、CommonJS和ECMAScript1、概念说明CommonJS和ECMAScript都是编写JS的标准。ECMAScript标准允许相同的js代码在不同的浏览器上执行得到相同的结果,是现有js语言的通用标准。CommonJS标准允许相同的js代码在Node.js环境下运行得到相同的结果,但它只是Node.js下的一个标准。2.有什么区别?Node.js既支持CommonJS标准,又完全支持ECMAScript标准。Node.js环境下js语言编写的文件有三种格式:.js、.mjs、.cjs。.mjs:此类文件只能被ECMAScript标准解析执行;.cjs:这类文件只能被CommonJS标准解析执行;特别说明,默认使用CommonJS标准解析和执行;case2:package.json文件中type属性值为默认值或等于commonjs,则使用CommonJS标准解析执行.js文件;如果type属性等于module,则使用ECMAScript标准解析执行.js文件。情况3:命令行中有一个flag,--input-type=module表示使用ECMAScript标准来解析执行.js文件;--input-type=commonjs表示使用CommonJS标准来解析执行.js文件。node--input-type=module--eval“从‘路径’导入{sep};console.log(sep);”回声“从'路径'导入{sep};console.log(sep);”|node--input-type=modulerequire只能导入CommonJS标准文件;导入支持两个标准文件导入。二、CommonJS标准的一个简单例子1、写一个模块在Node.js中,一个js文件被看成是一个模块。例如,下面的circle.js是一个导出两个方法的模块。//circle.jsconst{PI}=数学;exports.area=(r)=>PI*r**2;exports.circumference=(r)=>2*PI*r;2.在另一个js中导入模块在文件中使用circle.js模块方法实现代码复用。//foo.jsconstcircle=require('./circle.js');console.log(`半径为4的圆的面积为${circle.area(4)}`);三、ECMAScript标准的简洁性例1.写一个模块//addTwo.mjsfunctionaddTwo(num){returnnum+2;}export{addTwo};2.导入模块//app.mjsimport{addTwo}from'./addTwo.mjs';//打印:6console.log(addTwo(4));四、模块导入方式1、requirerequire只能用于加载CommonJS模块。/home/ry/projects/foo.js文件加载其他模块如下://foo.jsconstcircle1=require('./circle.js');constcircle2=require('../circle.js');constcircle3=require('/home/marco/circle.js');constcircle4=require('circle');constcircle5=require('./some-library');console.log(`半径为4的圆的面积是${circle.area(4)}`);找到导入模块的方法:./circle.js:在foo.js所在的文件夹中,去findandloadcircle.js../circle.js:findandloadcircle.js/home/marco/foo.js所在文件夹上层文件夹中的circle.js:按照这个绝对路径查找并加载circle.jscircle:先从Node.js构建模块去查找加载,没有去node_modules文件夹找到circle模块,会一直寻找上层文件夹,如下circle.js./some-library:先从项目根目录下寻找package.json,然后到foo.js所在文件夹,寻找两个索引模块,如果没有则返回Error:Cannotfindmodule'some-library'//1.package.json找到如下内容{"name":"some-library","main":"./lib/some-library.js"}//2.找到是否有索引.jsmodule./some-library/index.js//3.查找是否有index.node模块./some-library/index.node2、importCommonJS模块和ECMAScript模块都可以用import导入,三种使用方式//相对路径import{sep}from'./startup.js'import{sep}from'./config.mjs'//绝对路径import{sep}from'/home/project/startup.js'import{sep}from'/home/project/startup.mjs'//模块名,查找方式moduleisthesamerequireimport{sep}from'some-package'import.meta.url:indicatestheabsoluteURLofthemodule//通过模块的绝对URL来读取相对路径import的文件{readFileSync}来自'fs';constbuffer=readFileSync(newURL('./data.proto',import.meta.url));3.动态导入以上方法都是静态导入。在某些场景下,可以使用动态导入来延迟模块加载,以获得更好的页面体验CommonJS和ECMAScript都支持动态导入。//CommonJS动态导入import('/modules/my-module.js').then((module)=>{//对模块做点什么。});//ECMAScript动态导入import('/modules/my-module.mjs').then((module)=>{//对模块做点什么。});5.例子:选择解析标准如果Node.js项目根目录下有my-app.js和package.json两个文件,那么终端启动项目nodemy-app.js,每个模块会以什么标准导入经过?///home/project/my-app.js//my-app.js会被ES标准导入,因为在同一个文件夹的package.json中有type属性。//如果启动目录没有package.json,则使用上层目录的package.json设置//即使用ES标准importinit.jsimport'./startup/init.js';//根据./node_modules/commonjs-package/package.json中的type属性值//默认为commonjs标准,否则遵循属性值标准。import'commonjs-package';//根据./node_modules/commonjs-package/package.json中的type属性值//默认使用commonjs标准,否则使用属性值标准。import'./node_modules/commonjs-package/index.js';///home/project/package.json{"type":"module",}6.其他补充1.其他文件如果没有找到模块,系统会尝试其他后缀的文件,即:.js、.json,最后是.node.2。同一个对象第一次调用require('foo')后,模块对象会被缓存,再调用require('foo')只会返回缓存的对象,不会重新加载。3.内置模块内置模块的优先级最高。使用require('http')时,即使有相同的js模块名http.js,也会被忽略,使用内置模块http。当然可以使用require('node:http')让代码更容易理解。4.包装模块Node.js会对加载的模块进行函数包装,防止多个模块中全局变量名的冲突,并向模块传递几个必要的参数,方便编写模块代码。(function(exports,require,module,__filename,__dirname){//这里是实际的模块代码});5.在ECMAscript标准中,require用于创建example.mjs文件。这个后缀文件是一个ECMAscript标准,所以不能直接使用require,但是可以使用Node.js内置的模块Module来实现require。//example.mjsimport{createRequire}from'module';constrequire=createRequire(import.meta.url);//sibling-module.js是一个CommonJSmodule.constsiblingModule=require('./sibling-module');7.参考文档Node.js中的CommonJS和ECMAScript有什么区别?
