来自类型判断在JavaScript中,对变量进行类型校验是一件很麻烦的事情。如果单纯的使用typeof,就会遇到各种各样的问题。举几个简单的🌰:console.log(typeofnull)//'object'console.log(typeofnewArray)//'object'console.log(typeofnewString)//'object'后来大家发现Object.prototype.toString()方法判断变量类型。constgetTypeString=obj=>Object.prototype.toString.call(obj)getTypeString(null)//'[objectNull]'getTypeString('string')//'[objectString]'getTypeString(newString)//'[objectString]'通过代理toString()方法,可以获得一个类型的字符串,我们可以对这个字符串进行操作。constgetTypeString=obj=>{returnObject.prototype.toString.call(obj)}constisType=type=>{returnobj=>{returngetTypeString(obj)===`[object${type}]`}}constisArray=isType('Array')//这个方法一般换成Array.isArrayconstisNull=isType('Null')constisObject=isType('Object')constisRegExp=isType('RegExp')constisFunction=isType('Function')constisAsyncFunction=isType('AsyncFunction')isNull(null)//trueisObject({})//trueisRegExp(/\w/)//trueisFunction(()=>{})//trueisAsyncFunction(async()=>{})//trueBut,在Node.js中,内部其实有一套用于判断变量类型的API。而且功能极其丰富。除了基本类型的判断外,还支持对Promise对象、Date对象、各种ArrayBuffers的判断。consttypes=require('util/types')types.isDate(newDate)//truetypes.isPromise(newPromise(()=>{}))//truetypes.isArrayBuffer(newArrayBuffer(16))//JavaScript中真正的严格相等在判断对象、数组等变量是否相等的过程中,如果使用===,通常只会判断两个变量是否指向同一个内存地址。如果要判断对象的key对应的所有值是否相等,需要遍历两个对象。util中也提供了判断两个对象是否严格相等的方法:util.isDeepStrictEqual(val1,val2)constutil=require('util')constval1={name:'shenfq'}constval2={name:'shenfq'}console.log('val1===val2',val1===val2)//falseconsole.log('isDeepStrictEqual',util.isDeepStrictEqual(val1,val2))//true也可以用这个方法判断是否数组严格相等:constutil=require('util')constarr1=[1,3,5]constarr2=[1,3,5]console.log('arr1===arr2',arr1===arr2)//falseconsole.log('isDeepStrictEqual',util.isDeepStrictEqual(arr1,arr2))//trueErrorFirst&PromiseEarlyNodeAPIs都是ErrorFirst风格,即所有的异步函数都会接受一个回调函数,回调的one参数是错误对象。如果正常返回error对象,则为null,后面的参数为响应成功的结果。//下面是读取文件的例子constfs=require('fs')fs.readFile('nginx.log',(error,data)=>{if(error){//读取文件控制台失败.error(error)return}//读取文件成功并打印结果console.log(data)})Node8发布时,增加了一个promisify接口,将ErrorFirst风格的API转换为PromiseAPI。constfs=require('fs')constutil=require('util')constreadFile=util.promisify(fs.readFile)readFile('./2021-11-11.log',{encoding:'utf-8'}).then(text=>console.log(text)).catch(error=>console.error(error))但是后来很多人觉得这些原生API支持Promise的方式太繁琐,每个API都需要单独的层promisify方法的包装器。Node10发布时,原生模块增加了一个.promises属性,该属性下的所有API都是Promise风格的。constfs=require('fs').promisesfs.readFile('./2021-11-11.log',{encoding:'utf-8'}).then(text=>console.log(text)).catch(error=>console.error(error))注:在Node14之后,promisesAPI新增了一个导入方法,通过修改包名引入。constfs=require('fs/promises')fs.readFile('./2021-11-11.log',{encoding:'utf-8'}).then(text=>console.log(text)).catch(error=>console.error(error))除了将ErrorFirst风格的API转换为PromiseAPI之外,util还提供了一个callbackify方法将异步函数转换为ErrorFirst风格的函数。下面通过callbackify将基于promise的fs恢复为ErrorFirst风格的函数。constfs=require('fs/promises')constutil=require('util')constreadFile=util.callbackify(fs.readFile)readFile('./2021-11-12.log',{encoding:'utf-8'},(error,text)=>{if(error){console.error(error)return}console.log(text)})调试和输出如果你开发过Node服务,你应该用过debug模块。通过这个Modules可以在控制台看到更清晰的调试信息。constdebug=require('debug')constlog=debug('app')constuser={name:'shenfq'}log('currentuser:%o',user)其实通过util也可以达到类似的效果。debug:constdebug=require('debug')constlog=debug('app')constuser={name:'shenfq'}log('currentuser:%o',user)仅在启动时,需要更换DEBUG环境带有NODE_DEBUG的变量。仔细看上面的代码,应该会发现在log('currentuser:%o',user)方法前面的字符串中有一个%o占位符,表示这个地方会被一个对象填充(目的)。这类似于C或Python中的printf。同样,在util模块中,直接提供了一个格式化方法:util.format。const{format}=require('util')console.log(format('Currentuser:%o',{name:'shenfq',age:25}))除了%o占位符,不同的数据类型应该使用不同的占位符。JavaScript中的对象是一个非常复杂的东西。除了直接使用util.format加上%o占位符来格式化对象外,util还提供了一种名为inspect的方法来进行对象格式化。const{inspect}=require('util')constuser={age:25,name:'shenfq',work:{name:'coding',seniority:5}}console.log(inspect(user))查看inspect这样好像什么都没做,但是inspect方法还有第二个参数,用于格式化的时候做一些个性化的配置。depth:number:控制显示层次;sorted:boolean|功能:是否按照key的编码值进行排序;compact:boolean:是否单行显示;当然,以上只是部分配置,更详细的配置可以查看node文档。下面我们写几个案例:所有属性换行显示:inspect(user,{compact:false})只格式化对象第一层的值:inspect(user,{depth:0,compact:false})根据key值的编码倒序输出:inspect(user,{compact:false,sorted:(a,b)=>a
