溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何讓你的JS寫(xiě)得更漂亮

發(fā)布時(shí)間:2021-11-06 11:13:24 來(lái)源:億速云 閱讀:121 作者:iii 欄目:web開(kāi)發(fā)

本篇內(nèi)容介紹了“如何讓你的JS寫(xiě)得更漂亮”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

1. 按強(qiáng)類(lèi)型風(fēng)格寫(xiě)代碼

JS是弱類(lèi)型的,但是寫(xiě)代碼的時(shí)候不能太隨意,寫(xiě)得太隨意也體現(xiàn)了編碼風(fēng)格不好。下面分點(diǎn)說(shuō)明:

(1)定義變量的時(shí)候要指明類(lèi)型,告訴JS解釋器這個(gè)變量是什么數(shù)據(jù)類(lèi)型的,而不要讓解釋器去猜,例如不好的寫(xiě)法:

var num,
 str,
 obj;

聲明了三個(gè)變量,但其實(shí)沒(méi)什么用,因?yàn)榻忉屍鞑恢浪鼈兪鞘裁搭?lèi)型的,好的寫(xiě)法應(yīng)該是這樣的:

var num = 0,
 str = '',
 obj = null;

定義變量的時(shí)候就給他一個(gè)默認(rèn)值,這樣不僅方便了解釋器,也方便了閱讀代碼的人,他會(huì)在心里有數(shù)——知道這些變量可能會(huì)當(dāng)作什么用。

在這里小編建了一個(gè)前端學(xué)習(xí)交流扣扣群:132667127,我自己整理的最新的前端資料和高級(jí)開(kāi)發(fā)教程,如果有想需要的,可以加群一起學(xué)習(xí)交流

(2)不要隨意地改變變量的類(lèi)型,例如下面代碼:

var num = 5;
num = "-" + num;

第1行它是一個(gè)整型,第2行它變成了一個(gè)字符串。因?yàn)镴S最終都會(huì)被解釋成匯編的語(yǔ)言,匯編語(yǔ)言變量的類(lèi)型肯定是要確定的,你把一個(gè)整型的改成了字符串,那解釋器就得做一些額外的處理。并且這種編碼風(fēng)格是不提倡的,有一個(gè)變量第1行是一個(gè)整型,第10行變成了一個(gè)字符串,第20行又變成了一個(gè)object,這樣就讓閱讀代碼的人比較困惑,上面明明是一個(gè)整數(shù),怎么突然又變成一個(gè)字符串了。好的寫(xiě)法應(yīng)該是再定義一個(gè)字符串的變量:

var num = 5;
var sign = "-" + num;

(3)函數(shù)的返回類(lèi)型應(yīng)該是要確定的,例如下面不確定的寫(xiě)法:

function getPrice(count){
 if(count < 0) return "";
 else return count * 100;
}

getPrice這個(gè)函數(shù)有可能返回一個(gè)整數(shù),也有可能返回一個(gè)空的字符串。這樣寫(xiě)也不太好,雖然它是符合JS語(yǔ)法的,但這種編碼風(fēng)格是不好的。使用你這個(gè)函數(shù)的人會(huì)有點(diǎn)無(wú)所適從,不敢直接進(jìn)行加減乘除,因?yàn)槿绻祷刈址M(jìn)行運(yùn)算的話(huà)值就是NaN了。函數(shù)的返回類(lèi)型應(yīng)該是要確定的,如下面是返回整型:

function getPrice(count){
 if(count < 0) return -1;
 else return count * 100;
}

然后告訴使用者,如果返回-1就表示不合法。如果類(lèi)型確定,解釋器也不用去做一些額外的工作,可以加快運(yùn)行速度。

如何讓你的JS寫(xiě)得更漂亮

2. 減少作用域查找

(1)不要讓代碼暴露在全局作用域下

例如以下運(yùn)行在全局作用域的代碼:

<script>
 var map = document.querySelector("#my-map");
 map.style.height = "600px";
</script>

有時(shí)候你需要在頁(yè)面直接寫(xiě)一個(gè)script,要注意在一個(gè)script標(biāo)簽里面,代碼的上下文都是全局作用域的,由于全局作用域比較復(fù)雜,查找比較慢。例如上面的map變量,第二行在使用的時(shí)候,需要在全局作用域查找一下這個(gè)變量,假設(shè)map是在一個(gè)循環(huán)里面使用,那可能就會(huì)有效率問(wèn)題了。所以應(yīng)該要把它搞成一個(gè)局部的作用域:

<script>
!function(){
 var map = document.querySelector("#my-map");
 map.style.height = "600px";
}()
</script>

上面用了一個(gè)function制造一個(gè)局部作用域,也可以用ES6的塊級(jí)作用域。由于map這個(gè)變量直接在當(dāng)前的局部作用域命中了,所以就不用再往上一級(jí)的作用域(這里是全局作用域)查找了,而局部作用域的查找是很快的。同時(shí)直接在全局作用域定義變量,會(huì)污染window對(duì)象。

(2)不要濫用閉包

閉包的作用在于可以讓子級(jí)作用域使用它父級(jí)作用域的變量,同時(shí)這些變量在不同的閉包是不可見(jiàn)的。這樣就導(dǎo)致了在查找某個(gè)變量的時(shí)候,如果當(dāng)前作用域找不到,就得往它的父級(jí)作用域查找,一級(jí)一級(jí)地往上直到找到了,或者到了全局作用域還沒(méi)找到。因此如果閉包嵌套得越深,那么變量查找的時(shí)間就越長(zhǎng)。如下:

function getResult(count){
 count++;
 function process(){
 var factor = 2;
 return count * factor - 5;
 }
 return process();
}

上面的代碼定義了一個(gè)process函數(shù),在這個(gè)函數(shù)里面count變量的查找時(shí)間要高于局部的factor變量。其實(shí)這里不太適合用閉包,可以直接把count傳給process:

function getResult(count){
 count++;
 function process(count){
 var factor = 2;
 return count * factor - 5;
 }
 return process(count);
}

這樣count的查找時(shí)間就和factor一樣,都是在當(dāng)前作用域直接命中。這個(gè)就啟示我們?nèi)绻硞€(gè)全局變量需要頻繁地被使用的時(shí)候,可以用一個(gè)局部變量緩存一下,如下:

var url = "";
if(window.location.protocal === "https:"){
 url = "wss://xxx.com" + window.location.pathname + window.location.search;
}

頻繁地使用了window.location對(duì)象,所以可以先把它緩存一下:

var url = "";
var location = window.location;
if(location.protocal === "https:"){
 url = "wss://xxx.com" + location.pathname + location.search;
}

搞成了一個(gè)局變變量,這樣查找就會(huì)明顯快于全局的查找,代碼也可以寫(xiě)少一點(diǎn)。

如何讓你的JS寫(xiě)得更漂亮

3. 避免==的使用

這里你可能會(huì)有疑問(wèn)了,有些人喜歡用==,有些人喜歡用===,大家的風(fēng)格不一樣,你為什么要強(qiáng)制別人用===呢?習(xí)慣用==的人,不能僅僅是因?yàn)?=比===少敲了一次鍵盤(pán)。為什么不提倡用==呢?

(1)如果你確定了變量的類(lèi)型,那么就沒(méi)必要使用==了,如下:

if(typeof num != "undefined"){
} 
var num = parseInt(value);
if(num == 10){
}

上面的兩個(gè)例子都是確定類(lèi)型的,一個(gè)是字符串,一個(gè)是整數(shù)。就沒(méi)必要使用==了,直接用===就可以了。

(2)如果類(lèi)型不確定,那么應(yīng)該手動(dòng)做一下類(lèi)型轉(zhuǎn)換,而不是讓別人或者以后的你去猜這里面有類(lèi)型轉(zhuǎn)換,如下:

var totalPage = "5";
if(parseInt(totalPage) === 1){
}

(3)使用==在JSLint檢查的時(shí)候是不通過(guò)的:

if(a == b){
}

如下JSLint的輸出:

Expected ‘===’ and instead saw ‘==’. if(a == b){

(4)并且使用==可能會(huì)出現(xiàn)一些奇怪的現(xiàn)象,這些奇怪的現(xiàn)象可能會(huì)給代碼埋入隱患:

null == undefined //true
'' == '0' //false
0 == '' //true
0 == '0' //true
'
 ' == 0 //true
new String("abc") == "abc" //true
new Boolean(true) == true //true
true == 1 //true

上面的比較在用===的時(shí)候都是false,這樣才是比較合理的。例如第一點(diǎn)null居然會(huì)等于undefined,就特別地奇怪,因?yàn)閚ull和undefined是兩個(gè)毫無(wú)關(guān)系的值,null應(yīng)該是作為初始化空值使用,而undefined是用于檢驗(yàn)?zāi)硞€(gè)變量是否未定義。

這和第1點(diǎn)介紹強(qiáng)類(lèi)型的思想是相通的。

4. 合并表達(dá)式

如果用1句代碼就可以實(shí)現(xiàn)5句代碼的功能,那往往1句代碼的執(zhí)行效率會(huì)比較高,并且可讀性可能會(huì)更好

(1)用三目運(yùn)算符取代簡(jiǎn)單的if-else

如上面的getPrice函數(shù):

function getPrice(count){
 if(count < 0) return -1;
 else return count * 100;
}

可以改成:

function getPrice(count){
 return count < 0 ? return -1 : count * 100;
}

這個(gè)比寫(xiě)一個(gè)if-else看起來(lái)清爽多了。當(dāng)然,如果你寫(xiě)了if-else,壓縮工具也會(huì)幫你把它改三目運(yùn)算符的形式:

function getPrice(e){return 0>e?-1:100*e}

(2)連等

連等是利用賦值運(yùn)算表達(dá)式會(huì)返回所賦的值,并且執(zhí)行順序是從右到左的,如下:

overtime = favhouse = listingDetail = {...}

有時(shí)候你會(huì)看到有人這樣寫(xiě):

var age = 0;
if((age = +form.age.value) >= 18){
 console.log("你是成年人");
} else {
 consoe.log("小朋友,你還有" + (18 - age) + "就成年了");
}

也是利用了賦值表達(dá)式會(huì)返回一個(gè)值,在if里面賦值的同時(shí)用它的返回值做判斷,然后else里面就已經(jīng)有值了。上面的+號(hào)把字符串轉(zhuǎn)成了整數(shù)。

(3)自增

利用自增也可以簡(jiǎn)化代碼。如下,每發(fā)出一條消息,localMsgId就自增1:

chatService.sendMessage(localMsgId++, msgContent);

5. 減少魔數(shù)

例如,在某個(gè)文件的第800行,冒出來(lái)了一句:

dialogHandler.showQuestionNaire("seller", "sell", 5, true);

就會(huì)讓人很困惑了,上面的四個(gè)常量分別代表什么呢,如果我不去查一個(gè)那個(gè)函數(shù)的變量說(shuō)明就不能夠很快地意會(huì)到這些常量分別有什么用。這些意義不明的常量就叫“魔數(shù)”。

所以最好還是給這些常量取一個(gè)名字,特別是在一些比較關(guān)鍵的地方。例如上面的代碼可改成:

var naireType = "seller",
 dialogType = "sell",
 questionsCount = 5,
 reloadWindow = true;
naireHandler.showNaire(naireType, dialogType, questionsCount, reloadWindow);

這樣意義就很明顯了。

6. 使用ES6簡(jiǎn)化代碼

ES6已經(jīng)發(fā)展很多年了,兼容性也已經(jīng)很好了。恰當(dāng)?shù)厥褂?,可以讓代碼更加地簡(jiǎn)潔優(yōu)雅。

(1)使用箭頭函數(shù)取代小函數(shù)

有很多使用小函數(shù)的場(chǎng)景,如果寫(xiě)個(gè)function,代碼起碼得寫(xiě)3行,但是用箭頭函數(shù)一行就搞定了,例如實(shí)現(xiàn)數(shù)組從大到小排序:

var nums = [4, 8, 1, 9, 0];
nums.sort(function(a, b){
 return b - a;
});
//輸出[9, 8, 4, 1, 0]

如果用箭頭函數(shù),排序只要一行就搞定了:

var nums = [4, 8, 1, 9, 0];
nums.sort(a, b => b - a);

代碼看起來(lái)簡(jiǎn)潔多了,還有setTimeout里面經(jīng)常會(huì)遇到只要執(zhí)行一行代碼就好了,寫(xiě)個(gè)function總感覺(jué)有點(diǎn)麻煩,用字符串的方式又不太好,所以這種情況用箭頭函數(shù)也很方便:

setTimeout(() => console.log("hi"), 3000)

箭頭函數(shù)在C++/Java等其它語(yǔ)言里面叫做Lambda表達(dá)式,Ruby比較早就有這種語(yǔ)法形式了,后來(lái)C++/Java也實(shí)現(xiàn)了這種語(yǔ)法。

當(dāng)然箭頭函數(shù)或者Lambda表達(dá)式不僅適用于這種一行的,多行代碼也可以,不過(guò)在一行的時(shí)候它的優(yōu)點(diǎn)才比較明顯。

(2)使用ES6的class

雖然ES6的class和使用function的prototype本質(zhì)上是一樣的,都是用的原型。但是用class可以減少代碼量,同時(shí)讓代碼看起來(lái)更加地高大上,使用function要寫(xiě)這么多:

function Person(name, age){
 this.name = name;
 this.age = age;
}
Person.prototype.addAge = function(){
 this.age++;
};
Person.prototype.setName = function(name){
 this.name = name;
};

使用class代碼看加地簡(jiǎn)潔易懂:

class Person{
 constructor(name, age){
 this.name = name;
 this.age = age;
 }
 addAge(){
 this.age++;
 }
 setName(name){
 this.name = name;
 }
}

并且class還可以很方便地實(shí)現(xiàn)繼承、靜態(tài)的成員函數(shù),就不需要自己再去通過(guò)一些技巧去實(shí)現(xiàn)了。

(3)字符串拼接

以前要用+號(hào)拼接:

var tpl = 
 '<div>' + 
 ' <span>1</span>' +
 '</div>';

現(xiàn)在只要用兩個(gè)反引號(hào)“`”就可以了:

var tpl = 
` <div>
 <span>1</span>
 </div>
`;

另外反引號(hào)還支持占位替換,原本你需要:

var page = 5,
 type = encodeURIComponet("#js");
var url = "/list?page=" + page + "&type=" + type;

現(xiàn)在只需要:

var url = `/list?page=${page}&type=${type}`;

就不用使用+號(hào)把字符串拆散了。

(4)塊級(jí)作用域變量

塊級(jí)作用域變量也是ES6的一個(gè)特色,下面的代碼是一個(gè)任務(wù)隊(duì)列的模型抽象:

var tasks = [];
for(var i = 0; i < 4; i++){
 tasks.push(function(){
 console.log("i is " + i);
 });
}
for(var j = 0; j < tasks.length; j++){
 tasks[j]();
}

但是上面代碼的執(zhí)行輸出是4,4,4,4,并且不是想要輸出:0,1,2,3,所以每個(gè)task就不能取到它的index了,這是因?yàn)殚]包都是用的同一個(gè)i變量,i已經(jīng)變成4了,所以執(zhí)行閉包的時(shí)候就都是4了。那怎么辦呢?可以這樣解決:

var tasks = [];
for(var i = 0; i < 4; i++){
 !function(k){
 tasks.push(function(){
 console.log("i is " + k);
 });
 }(i);
}
for(var j = 0; j < tasks.length; j++){
 tasks[j]();
}

把i賦值給了k,由于k它是一個(gè)function的一個(gè)參數(shù),每次執(zhí)行函數(shù)的時(shí)候,肯定會(huì)實(shí)例化新的k,所以每次的k都是不同的變量,這樣就輸出就正常了。

但是代碼看起來(lái)有點(diǎn)別扭,如果用ES6,只要把var改成let就可以了:

var tasks = [];
for(let i = 0; i <= 4; i++){
 tasks.push(function(){
 console.log("i is " + i);
 });
}
for(var j = 0; j < tasks.length; j++){
 tasks[j]();
}

只改動(dòng)了3個(gè)字符就達(dá)到了目的。因?yàn)閒or循環(huán)里面有個(gè)大括號(hào),大括號(hào)就是一個(gè)獨(dú)立的作用域,let定義的變量在獨(dú)立的作用域里面它的值也是獨(dú)立的。當(dāng)然即使沒(méi)寫(xiě)大括號(hào)for循環(huán)執(zhí)行也是獨(dú)立的。

除了以上幾點(diǎn),ES6還有其它一些比較好用的功能,如Object的assign,Promise等,也是可以幫助寫(xiě)出簡(jiǎn)潔高效的代碼。

“如何讓你的JS寫(xiě)得更漂亮”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

js
AI