当前位置: 首页 > 科技观察

如何让你的JS写的更漂亮

时间:2023-03-16 15:03:41 科技观察

网上关于优化JS写法的建议很多,这里我根据自己的经验提出一些有用的建议。1.以强类型风格编写代码。JS是弱类型的,但是写代码的时候不能太随意。写得太随意也反映了一种糟糕的编码风格。解释如下几点:(1)定义变量时,指定类型,告诉JS解释器该变量是什么数据类型,不要让解释器猜,比如写的不好:varnum,str,obj;declared三个变量,但是没用,因为解释器不知道它们是什么类型,好的写法应该是这样:varnum=0,str='',obj=null;在定义一个变量的时候,给他一个默认值,这样既方便了解释器,也方便了阅读代码的人。他会知道这些变量可能有什么用。(2)不要随意改变变量的类型,比如下面的代码:varnum=5;num="-"+num;它在第一行是一个整数,在第二行变成一个字符串。因为JS最终会被解释成汇编语言,所以必须确定汇编语言变量的类型。如果你把一个整数变成一个字符串,解释器将不得不做一些额外的处理。并且不提倡这种编码风格。有一个变量,第一行是一个整数,第10行变成了一个字符串,第20行变成了一个对象,看代码的人很迷惑,上面明明是整数,怎么突然又变成字符串了。一个好的写法应该是再定义一个字符串变量:varnum=5;varsign="-"+num;(3)函数的返回类型要确定,比如下面不确定的写法:functiongetPrice(count){if(count<0)return"";elsereturncount*100;}getPrice这个函数可能返回一个整数或空字符串。这样写不太好。虽然符合JS语法,但是这种编码风格并不好。用你这个函数的人会有点不知所措,不敢直接加减乘除,因为如果返回字符串计算的话,这个值就是NaN。应该确定函数的返回类型。比如返回类型是这样的:functiongetPrice(count){if(count<0)return-1;elsereturncount*100;}然后告诉用户,如果返回-1,就是非法的。如果确定了类型,解释器就不需要做一些额外的工作,可以加快运行速度。2.减少范围搜索(1)不要将代码暴露在全局范围内。比如下面在全局范围内运行的代码:有时候需要写一个脚本直接在页面上。请注意,在脚本标记中,代码的上下文处于全局范围内。因为全局范围比较复杂,所以搜索比较慢。比如上面的map变量,在使用第二行的时候,需要在全局范围内查找这个变量。假设在循环中使用map,可能会出现效率问题。所以应该做成局部作用域:上面的使用函数创建局部作用域,也可以使用ES6块级作用域。由于变量map是在当前局部作用域直接命中的,不需要向上层作用域(这里是全局作用域)查找,在局部作用域查找非常快。同时,直接在全局范围内定义变量会污染window对象。(2)不要滥用闭包闭包的作用是让子级作用域可以使用其父级作用域中的变量,而这些变量在不同的闭包中是不可见的。这就导致了在查找变量时,如果在当前作用域中找不到,就必须在其父作用域中逐层查找,直到找到,否则在全局作用域中还没有找到。.所以闭包嵌套得越深,变量查找的时间就越长。如下:functiongetResult(count){count++;functionprocess(){varfactor=2;returncount*factor-5;}returnprocess();}以上代码定义了一个过程函数,其中count变量的查找时间高于局部因子变量。其实这里不适合用闭包,可以直接把count传给进程:functiongetResult(count){count++;functionprocess(count){varfactor=2;returncount*factor-5;}returnprocess(count);}这样的countlookupTime和factor一样,直接命中当前作用域。这启发我们,如果一个全局变量需要经常使用,我们可以使用一个局部变量来缓存它,如下:varurl="";if(window.location.protocal==="https:"){url="wss://xxx.com"+window.location.pathname+window.location.search;}window.location对象经常使用,可以先缓存起来:varurl="";varlocation=window.location;if(location.protocal==="https:"){url="wss://xxx.com"+location.pathname+location.search;}变成局部变量,所以搜索速度会明显加快对于全局搜索,代码也可以少写。3、避免使用==这里大家可能会有疑惑,有人喜欢用==,有人喜欢用===,每个人的风格不一样,为什么要强行让别人用===呢?习惯上用=有=的人不能只因为==比===少了一次击键。为什么不提倡使用==?(1)如果判断变量的类型,那么就不用==了,如下:if(typeofnum!="undefined"){}varnum=parseInt(value);if(num==10){}上面两个例子是有一定类型的,一个是字符串,一个是整数。不用==,直接用===就可以了。(2)如果不确定类型,那么你应该手动做一个类型转换,而不是让别人或者你以后猜测有类型转换,如下:vartotalPage="5";if(parseInt(totalPage)===1){}(3)在JSLint中检查时使用==不通过:if(a==b){}JSLint的输出如下:Expected'==='andinsteadsaw'=='。if(a==b){(4)而使用==可能会导致一些奇怪的现象,可能会在代码中埋下隐患:null==undefined//true''=='0'//false0==''//true0=='0'//true''==0//truenewString("abc")=="abc"//truenewBool??ean(true)==true//truetrue==1//true上面的使用===时比较为false,比较合理。比如第一点,null等于undefined,这就很奇怪了,因为null和undefined是两个不相干的值。null应该用作初始化的空值,undefined用于检查变量是否未定义。这个和第1点引入强类型的思路类似。4.如果组合表达式可以用1个代码实现5个代码的功能,那么1个代码的执行效率会更高,可读性可能会更好(1)用三元运算符代替简单的if-else如上面的getPrice函数:functiongetPrice(count){if(count<0)return-1;elsereturncount*100;}可以改成:functiongetPrice(count){returncount<0?return-1:count*100;这看起来比编写if-else干净得多。当然,如果你写if-else,压缩工具也会帮你改成三元运算符的形式:functiongetPrice(e){return0>e?-1:100*e}(2)等yesUsing赋值运算表达式会返回赋值,执行顺序是从右到左,如下:overtime=favhouse=listingDetail={...}有时你会看到有人这样写:varage=0;if((age=+form.age.value)>=18){console.log("你是成年人");}else{consoe.log("孩子们,你还有"+(18-age)+"我是anadult");}也是用赋值表达式返回一个值,在if里赋值的时候用它的返回值做判断,然后else里已经有值了。上面的+号将字符串转换为整数。(3)自增使用自增还可以简化代码。如下,每发送一条消息,localMsgId都会加1:chatService.sendMessage(localMsgId++,msgContent);5.减少magicnumber",sell",5,true);会让人很疑惑,上面四个常量代表什么,如果不查看那个函数的变量说明,我是无法快速理解的这些常量是做什么用的呢?这些意义不明的常量被称为“幻数”。所以最好给这些常量起个名字,尤其是在一些比较关键的地方。比如上面的代码可以改成:varnaireType="seller",dialogType="sell",questionsCount=5,reloadWindow=true;naireHandler.showNaire(naireType,dialogType,questionsCount,reloadWindow);所以意思很明显。6.使用ES6简化代码ES6发展多年,而且兼容性已经很好了,适当的使用可以让代码更加简洁优雅。(1)使用箭头函数代替小函数。用到小函数的场景有很多。如果写一个函数,至少需要写3行代码,但是一行箭头函数就搞定了。例如数组从大到小排序:varnums=[4,8,1,9,0];nums.sort(function(a,b){returnb-a;});//输出[9,8,4,1,0]如果使用箭头函数,排序只需要一行即可:varnums=[4,8,1,9,0];nums.sort(a,b=>b-a);代码看起来简洁多了,经常遇到setTimeout只需要执行一行代码就可以了,写一个函数总感觉有点繁琐,而且使用字符串的方法也不是很好,所以就这样了在这种情况下使用箭头函数也很方便:setTimeout(()=>console.log("hi"),3000)箭头函数在C++/Java等语言中被称为Lambda表达式。Ruby早有这种语法形式,后来C++/Java也实现了这种语法。当然,箭头函数或者Lambda表达式不仅适用于这种单行代码,也适用于多行代码,只是单行时其优势更加明显。(2)使用ES6class尽管ES6class和prototypeusingfunction本质上是一样的,但都是原型。但是使用class可以减少代码量,同时让代码看起来更高大上。使用函数需要写这么多:functionPerson(name,age){this.name=name;this.age=age;}Person.prototype.addAge=function(){this.age++;};Person.prototype.setName=function(名字){this.name=名字;};使用类代码看简洁易懂:classPerson{constructor(name,age){this.name=name;this.age=age;}addAge(){this.age++;}setName(name){this.name=name;}}和class也可以很方便的实现继承和静态成员函数,就不用你了需要通过一些技巧才能自己实现。(3)字符串拼接前,需要使用+号拼接:vartpl='

'+'1'+'
';现在只要用两个反引号"`"就可以了:vartpl=`
1
`;另外,反引号也支持占位符替换,原来需要:varpage=5,type=encodeURIComponet("#js");varurl="/list?page="+page+"&type="+type;现在只需要:varurl=`/list?page=${page}&type=${type}`;你不需要使用+号来把字符串分崩离析。(4)块级作用域变量块级作用域变量也是ES6的一个特性。下面的代码是一个任务队列的模型抽象:vartasks=[];for(vari=0;i<4;i++){tasks.push(function(){console.log("iis"+i);});}for(varj=0;j