在项目开发过程中,会发现有一些代码反复需要,这些大部分是有第三方的脚本库来解决,有时不想为了一个功能安装一整个库,因此建议平时开发过程中将常用的函数封装成一个公共库。本文将带总结一下项目开发过程中可以用得到的函数。
1. 类型检查
JavaScript不是强类型语言,为了达到这个目的,最好的解决方案是 TypeScript,推荐在项目中使用 TypeScript,通常对于一些简单的类型检查,可以使用 typeof
。
typeof
的问题在于,如果将它用于原始类型和函数,它会很好用,但对于数组和对象,就不那么好用了,因为它们返回的都是 objects
。
consttypeChecker=(()=>{consttype=Object.create(null);//nulltype.null=(x)=>x===null;//undefinedtype.undefined=(x)=>x===undefined;//nilnullundefinedtype.nil=(x)=>type.null(x)||type.undefined(x);//stringtype.string=(x)=>!type.nil(x)&&(typeofx==="string"||xinstanceofString);//numbertype.number=(x)=>!type.nil(x)&&//NaN&Infinityhavetypeof"number"andthisexcludesthat((!isNaN(x)&&isFinite(x)&&typeofx==="number")||xinstanceofNumber);//booleantype.boolean=(x)=>!type.nil(x)&&(typeofx==="boolean"||xinstanceofBoolean);//arraytype.array=(x)=>!type.nil(x)&&Array.isArray(x);//object.e.g:{},newObject(),Object.create(null)type.object=(x)=>({}.toString.call(x)==="[objectObject]");//checkforprovidedtypeinstancetype.type=(x,X)=>!type.nil(x)&&xinstanceofX;//settype.set=(x)=>type.type(x,Set);//maptype.map=(x)=>type.type(x,Map);//datetype.date=(x)=>type.type(x,Date);returntype;})();
2. 创建类私有方法
JavaScript 有自己的方法来创建类私有成员,但目前还处于ES2020试验草案中,并且语法比较奇怪,以 #
作为前缀。下面代码片段使用闭包、作用域来实现类的私有域。
constHelper=(()=>{constdefaultValue=(val,defVal)=>{if(val&&val!==""){returnval;}else{returndefVal;}};constapiEndpoint="/Auth";//对外暴露的类classUtility{constructor(){this.loginPath=`${apiEndpoint}/login`;}getVal(key,defVal){returndefaultValue(key,defVal);}}returnUtility;})();consttestHelper=newHelper();console.log(testHelper.getVal(undefined,0));//0console.log(testHelper.loginPath);///Auth/login
3. 检查是否为空
有时只需要知道某些内容是否为空,并且根据要检查的内容,需要使用不同的方法,例如检查长度、大小或是否包含子元素。
下面代码片段封装了所有情况下的空值验证,包括 String
、Object
、Array
、Map
和 Set
。
constisEmpty=(x)=>{if(Array.isArray(x)||typeofx==="string"||xinstanceofString){returnx.length===0;}if(xinstanceofMap||xinstanceofSet){returnx.size===0;}if({}.toString.call(x)==="[objectObject]"){returnObject.keys(x).length===0;}returnfalse;};console.log(isEmpty(newSet()));//trueconsole.log(isEmpty({}));//true
4. 获取集合最后一项
其他语言将此作为可以在数组上调用的方法或函数,但对于 JavaScript,需要自己编码实现这些工作,这里的集合包括 Array
、Set
、Map
。
constlastItem=(list)=>{if(Array.isArray(list)){returnlist.slice(-1)[0];}if(listinstanceofSet){returnArray.from(list).slice(-1)[0];}if(listinstanceofMap){returnArray.from(list.values()).slice(-1)[0];}};consttestSet=newSet();testSet.add(1);testSet.add(2);console.log(lastItem(testSet));//2
5. 随机数生成
随机数是一个常见的需求,生成指定范围的随机数。
constrandomNumber=(max=1,min=0)=>{if(min>=max){[min,max]=[max,min];}returnMath.floor(Math.random()*(max-min)+min);};console.log(randomNumber(1,100));
6. 随机 ID 生成器
生成唯一 ID,之前有介绍过 nano 或者 UUID,这里介绍一种简单的方式,足够应对大部分的项目需求,以从当前时间(以毫秒为单位)或特定的整数和增量开始,也可以从字母数字字符生成ID。
//创建从当前时间开始的唯一id(以毫秒为单位),每次请求时加1constuniqueId=((mil)=>()=>mil++)(Date.now());//创建指定长度的数字组成的唯一递增IDconstuniqueIncrementingId=((numb)=>(length=12)=>`${numb++}`.padStart(length,"0"))(1);//创建字母和数字组成的唯一idconstuniqueAlphaNumericId=(()=>{constheyStack="0123456789abcdefghijklmnopqrstuvwxyz";const{length}=heyStack;constrandomInt=()=>Math.floor(Math.random()*length);return(length=24)=>Array.from({length},()=>heyStack[randomInt()]).join("");})();console.log(uniqueId());//1633317380617console.log(uniqueIncrementingId());//000000000001console.log(uniqueIncrementingId());//000000000002console.log(uniqueAlphaNumericId());//e7r5y71cvfo18ccj1sgp70ts
7. 创建一系列数字
在 Python 中的有一个函数 range
,可以随机生成一系列数字,在 JavaScript 中需要自己编码实现。
constrange=(maxOrStart,end=null,step=null)=>{if(!end){returnArray.from({length:maxOrStart},(_,i)=>i);}if(end<=maxOrStart){return[];}if(step!==null){returnArray.from({length:Math.ceil((end-maxOrStart)/step)},(_,i)=>i*step+maxOrStart);}returnArray.from({length:Math.ceil(end-maxOrStart)},(_,i)=>i+maxOrStart);};console.log(range(10,20,3));//[10,13,16,19]
8. 格式化 JSON 字符串
在使用NodeJs将对象记录到控制台时经常使用 JSON.Stringify()
,其接受三个参数,语法如下:
JSON.stringify(value[,replacer[,space]])
value
:将要序列化成 一个 JSON 字符串的值。
replacer
:可选,如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
space
:可选,指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。
conststringify=(()=>{constreplacer=(key,val)=>{if(typeofval==="symbol"){returnval.toString();}if(valinstanceofSet){returnArray.from(val);}if(valinstanceofMap){returnArray.from(val.entries());}if(typeofval==="function"){returnval.toString();}returnval;};return(obj,spaces=0)=>JSON.stringify(obj,replacer,spaces);})();consttestSet=newSet();testSet.add(1);testSet.add(2);consttestMap=newMap();testMap.set("title","DevPoint");consttestObj={title:"DevPoint",};console.log(stringify(testSet));//[1,2]console.log(stringify(testMap));//[["title","DevPoint"]]console.log(stringify(testObj));//{"title":"DevPoint"}
9. 函数链
使用过 jQuery 的开发者应该很清楚函数链,初次见到这种方式的时候感觉很酷,如将多个函数与相同的元素引用链接在一起,没有必要为每个函数调用多次附加元素引用。
constselectedDiv=$("#myDiv");//函数链方式selectedDiv.css("color:red").height("100px").width("100px");//非函数链selectedDiv.css("color:red");selectedDiv.height("100px");selectedDiv.width("100px");
一般在项目开发中的公共方法类可以考虑支持函数链,可以为其提供简洁的调用方式,下面代码展示了函数链的实现:
constHelper=(()=>{constdefaultValue=(val,defVal)=>{if(val&&val!==""){returnval;}else{returndefVal;}};constapiEndpoint="/Auth";//对外暴露的类classUtility{constructor(){this.loginPath=`${apiEndpoint}/login`;}getVal(key,defVal){returndefaultValue(key,defVal);}}returnUtility;})();consttestHelper=newHelper();console.log(testHelper.getVal(undefined,0));//0console.log(testHelper.loginPath);///Auth/login0
总结
定期总结项目开发中出现频率比较高的方法,去优化其是否为最佳,并为后期项目开发提供弹药。