23 個 JavaScript 最佳實踐 - 最實用篇

1. 使用 === 代替 ==
JavaScript 使用兩種不同的相等運算符: === 和 !==是嚴格相等運算符,而 == 和 != 是非嚴格運算符。當二者相比較時始終使用嚴格相等被認為是最佳實踐。
“如果兩個操作數(shù)的類型和值相同,則 ===產(chǎn)生真,而 !==產(chǎn)生假。” ---- 來自JavaScript:好的部分
但是,在使用 == 和 !=時,你會發(fā)現(xiàn)在使用不同類型時會一些遇到問題。當您比較的值具有不同類型時,非嚴格運算符將嘗試強制轉(zhuǎn)換它們的值,您可能會得到意想不到的結(jié)果。
2. eval() 不好
對于當初不熟悉時,該 eval() 函數(shù)使我們能夠訪問 JavaScript 的編譯器。本質(zhì)上,我們可以通過將字符串傳遞給eval() 作為參數(shù)來執(zhí)行字符串的結(jié)果。
這不僅會顯著降低腳本的性能,而且還會帶來巨大的安全風險,因為這樣付給要執(zhí)行的文本太高的權(quán)限。所以我們盡量躲開它!
3. 不要使用簡寫
從技術(shù)上講,您可以省略大多數(shù)花括號和分號。大多數(shù)瀏覽器會正確解釋以下內(nèi)容:
if(someVariableExists)
x = false
但是,請考慮:
if(someVariableExists)
x = false
anotherFunctionCall();
}
有人可能認為上面的代碼等價于:
if(someVariableExists) {
x = false;
anotherFunctionCall();
}
不幸的是,他錯了。實際上,這意味著:
if(someVariableExists) {
x = false;
}
anotherFunctionCall();
您可能會注意到,上面縮進容易給人花括號的功能的假象。不用說,這是一種可怕的實踐,應(yīng)該不惜一切代價去避免?;ɡㄌ枒?yīng)該被省略的唯一一次是單行的時候,即使這是一個備受爭議的話題。
if(2 + 2 === 4) return 'nicely done';
要做到未雨綢繆
如果以后需要向此 if 語句添加更多命令,該怎么辦呢?為此,您需要重寫此代碼塊。底線--在省略時需謹慎行事。
4. 使用 JS Lint
JSLint 是由 Douglas Crockford 編寫的調(diào)試器。簡單的只需粘貼您的腳本進去,它就會快速掃描您代碼中的任何明顯問題和錯誤。
“JSLint 獲取 JavaScript 源代碼并對其進行掃描。如果發(fā)現(xiàn)問題,它會返回一條描述問題的消息以及源代碼中的大致位置。問題不一定是語法錯誤,盡管通常是這樣。JSLint h還會查看一些編碼風格和程序結(jié)構(gòu)問題,它并不能證明您的程序是正確的。它只是提供了另一雙眼睛來幫助發(fā)現(xiàn)問題?!?- JSLint 文檔
在部署腳本之前,請通過 JSLint 運行它,以確保您沒有犯任何無意識的錯誤。
5. 將腳本放在頁面底部
此技巧已在本系列的前一篇文章中推薦(后續(xù)更新)。由于它非常合適,我將粘貼信息。
cahtu
請記住——主要目標是讓用戶盡快加載頁面。腳本加載并執(zhí)行完成之前,瀏覽器不能繼續(xù)渲染下面內(nèi)容。因此,用戶將不得不等待更長時間來注意到任何進展。
如果您的 JS 文件的唯一目的是添加功能(例如,按鈕的單擊事件),馬上將腳本放在body結(jié)束之前。這絕對是最佳實踐。
建議
<p>And now you know my favorite kinds of corn. </p>
<script type="text/javascript" src="path/to/file.js"></script>
<script type="text/javascript" src="path/to/anotherFile.js"></script>
</body>
</html>
6. 在 For 語句之外聲明變量
在執(zhí)行冗長的 for 語句時,要保持語句塊的盡量簡潔。例如:
糟糕的
or(var i = 0; i < someArray.length; i++) {
var container = document.getElementById('container');
container.innerHtml += 'my number: ' + i;
console.log(i);
}
請注意我們在每次迭代時需計算數(shù)組的長度,以及我們每次都要遍歷 DOM 以查找“container”元素——可見效率極低!
建議
var container = document.getElementById('container');
for(var i = 0, len = someArray.length; i < len; i++) {
container.innerHtml += 'my number: ' + i;
console.log(i);
}
7. 構(gòu)建字符串的最快方法
當您需要循環(huán)遍歷數(shù)組或?qū)ο髸r,不要總是使用方便的for 語句。發(fā)揮創(chuàng)造力,為手頭的工作找到最快的解決方案。
var arr = ['item 1', 'item 2', 'item 3', ...];
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';
我不是所謂的神人,但你只需要相信我(或自己測試)——這是迄今為止最快的方法!
無論抽象層后面發(fā)生了什么,使用像join()的本機方法,通常比任何非本機替代方法快得多?!?來自 James Padolsey, james.padolsey.com
8. 使用模板文字
我們用雙引號或單引號創(chuàng)建的字符串有很多限制。您可能想用模板文字替換一些字符串,以便更輕松地使用它們。模板文字是使用反引號字符 ``` 來創(chuàng)建的,它們具有許多優(yōu)點。您可以將表達式放入其中或創(chuàng)建多行字符串。
let person = 'Monty';
let fruits = 'apples';
let activity = 'playing games';
let day = 'Monday';
var sentence = person + ' will be eating ' + fruits + ' and ' + activity + ' on ' + day + '.';
console.log(sentence);
// Output: Monty will be eating apples and playing games on Monday.
var sentence = `${person} will be eating ${fruits} and ${activity} on ${day}.`;
console.log(sentence);
// Output: Monty will be eating apples and playing games on Monday.
如您所見,我們不必像使用單引號或雙引號創(chuàng)建的常規(guī)字符串文字那樣不斷地移入和移出文字模板。這減少了任何輸入相關(guān)錯誤的機會,并幫助我們編寫更清晰的代碼。
減少全局變量
“只要把多個全局變量都整理在一個名稱空間下,擬將顯著降低與其他應(yīng)用程序、組件或類庫之間產(chǎn)生糟糕的相互影響的可能性?!?—- Douglas Crockford
var name = 'Jeffrey';
var lastName = 'Way';
function doSomething() {...}
console.log(name); // Jeffrey -- or window.name
建議
var DudeNameSpace = {
name : 'Jeffrey',
lastName : 'Way',
doSomething : function() {...}
}
console.log(DudeNameSpace.name); // Jeffrey
注:這里只是簡單命名為 DudeNameSpace ,實際當中要取更合理的名字。
10. 考慮使用 let 和 const
該 let 關(guān)鍵字允許我們創(chuàng)建在自己的區(qū)塊內(nèi)范圍的局部變量。該 const 關(guān)鍵字允許我們創(chuàng)建其值但不能重新分配局部塊范圍變量。你應(yīng)該在適當?shù)膱龊峡紤]使用關(guān)鍵字 let 和 const 聲明的變量。請記住,關(guān)鍵字 const只能防止重新分配。它不會使變量不可變。
var person_name = "Adam";
let name_length = person_name.length;
const fav_website = "code.tutsplus.com";
if(person_name.length < 5) {
var person_name = "Andrew";
let name_length = person_name.length;
// Throws an error if commented out!
// fav_website = "webdesign.tutsplus.com";
console.log(`${person_name} has ${name_length} characters.`);
// Output: Andrew has 6 characters.
}
console.log(`${person_name} has ${name_length} characters.`);
// Output: Andrew has 4 characters.
在上面的例子中, 我們在塊內(nèi)修改變量person_name 后,變量的值 if塊也在外更新 。另一方面,name_length是塊范圍的,因此它在塊之外保留了其原始值。
11. 注釋你的代碼
乍一看似乎沒有必要,但相信我,您最好盡可能地注釋您的代碼。當你幾個月后回到項目時(這過程可能會發(fā)生什么),卻發(fā)現(xiàn)你無法輕易記住你的思路?;蛘?,如果您的一位同事需要修改您的代碼怎么辦?所以,始終注釋代碼的才是重要的。
// Cycle through array and echo out each name.
for(var i = 0, len = array.length; i < len; i++) {
console.log(array[i]);
}
12. 擁抱漸進式增強
確保在 JavaScript 被禁用的情況下能平穩(wěn)退化。你可能會想,“我的大多數(shù)訪客都啟用了 JavaScript,所以我不會擔心?!?然而,這是一個很大的錯誤。
您是否曾花點時間來查看你漂亮的頁面在 JavaScript 被關(guān)閉是是什么樣的?(下載 Web Developer 工具就可以很容易做到 )它有可能會完全破壞您的網(wǎng)站。根據(jù)經(jīng)驗,設(shè)計您的網(wǎng)站時假設(shè) JavaScript 是被禁用的。然后,在此基礎(chǔ)上,逐步增強您的網(wǎng)站!
13. 不要將字符串傳遞給 setInterval 或 setTimeOut
考慮以下代碼:
setInterval(
"document.getElementById('container').innerHTML += 'My new number: ' + i", 3000
);
這段代碼不僅效率低下,而且還以與eval函數(shù)相同的方式運行。永遠不要將字符串傳遞給setInterval and setTimeOut。而是像以下方式傳遞函數(shù)名稱。
setInterval(someFunction, 3000);
14. 使用 {} 代替 new Object()
在 JavaScript 中有多種創(chuàng)建對象的方法。也許更傳統(tǒng)的方法是使用 new 加構(gòu)造函數(shù),如下所示:
var o = new Object();
o.name = 'Jeffrey';
o.lastName = 'Way';
o.someFunction = function() {
console.log(this.name);
}
然而,這種方受到的詬病不及實際上多。作為代替,我建議您使用對象字面量方法。
更好的做法
var o = new Object();
o.name = 'Jeffrey';
o.lastName = 'Way';
o.someFunction = function() {
console.log(this.name);
}
請注意,如果您只是想創(chuàng)建一個空對象, {}就可以。
var o = {};
“對象字面量使我們能夠編寫更具特色的代碼,,而且相對簡單的多。無需直接調(diào)用構(gòu)造函數(shù)或維持傳遞給函數(shù)的參數(shù)的正確順序等?!?—-來自dyn-web.com
使用 [] 代替 new Array()
這同樣適用于創(chuàng)建一個新數(shù)組。
例如:
var a = new Array();
a[0] = "Joe";
a[1] = 'Plumber';
更好的做法:
var a = ['Joe','Plumber'];
“JavaScript 程序中的一個常見錯誤是在需要數(shù)組時使用對象或在需要對象時使用數(shù)組。規(guī)則很簡單:當屬性名是連續(xù)整數(shù)時,您應(yīng)該使用數(shù)組。否則,請使用對象?!?— Douglas Crockford
使用擴展運算符
您是否曾經(jīng)遇到過想要將數(shù)組的所有項目作為單獨元素傳遞給其他函數(shù)的情況,或者想要將一個數(shù)組中的所有值插入到另一個數(shù)組中?展開運算符 ... 可允許我們做到這一點。下面是一個例子:
let people = ["adam", "monty", "andrew"]
let more_people = ["james", "jack", ...people, "sajal"]
console.log(more_people)
// Output: Array(6) [ "james", "jack", "adam", "monty", "andrew", "sajal" ]
17. for in 語句
當遍歷對象屬性時,您可能會發(fā)現(xiàn)您還會檢索方法函數(shù)。為了解決這個問題,請始終將您的代碼包裹在 if 語句中過濾(信息。
for(key in object) {
if(object.hasOwnProperty(key) {
...then do something...
}
}
這個技巧來自 JavaScript: The Good Parts,作者是 Douglas Crockford。
18. 閱讀,閱讀,閱讀......
雖然我是 Web 開發(fā)博客的忠實粉絲(就像這個?。?,但在吃午飯或睡覺前,實在沒有一本書更合適了。堅持在床頭柜上放一本 Web 開發(fā)書。以下是我最喜歡的一些 JavaScript。
《 Object-Oriented JavaScript 》 《 JavaScript: The Good Parts 》 《 Learning JavaScript 》
要多去閱讀它們。直到現(xiàn)在我還會依舊反復(fù)閱讀!
自執(zhí)行函數(shù) 這不是調(diào)用函數(shù),而是在頁面加載或調(diào)用父函數(shù)時使函數(shù)自動運行,這非常簡單。只需將您的函數(shù)用圓括號包裹起來,然后附加一個額外的設(shè)置,它本質(zhì)上就是調(diào)用該函數(shù)。
(function doSomething() {
return {
name: 'jeff',
lastName: 'way'
};
})();
20. 原生代碼永遠比庫快
JavaScript 庫,例如 jQuery 和 lodash,可以在編碼時為您節(jié)省大量時間,尤其是 AJAX 操作。話雖如此,請記住,庫永遠不會比原生 JavaScript 代碼更快(假設(shè)您代碼正確)。
jQuery 的 each()方法非常棒的循環(huán),但使用原生 for 語句總是會快一些。
21.使用解構(gòu)快速分配變量值
我們已經(jīng)在本文前面了解了 JavaScript 中的展開運算符。解構(gòu)有點類似,因為它也解包存儲在數(shù)組中的值。不同之處在于我們可以將這些未打包的值分配給唯一變量。
語法類似于使用[]速記來創(chuàng)建數(shù)組 。但是,這次括號位于賦值運算符的左側(cè)。下面是一個例子:
let [person, fruit, , day] = ['Monty', 'apple', 'reading', 'tomorrow'];
var sentence = `${person} will eat an ${fruit} ${day}.`;
console.log(sentence);
// Output: Monty will eat an apple tomorrow.
您是否注意到我們只是將第三個數(shù)組元素分配給任何變量而不用通過傳遞變量名?這使我們可以避免對不需要的值進行變量賦值。
22. 迭代器和 for...... of 循環(huán)
JavaScript 中的迭代器是實現(xiàn) next()方法以返回一個對象的對象,該對象按順序存儲下一個值, true 或 false 取決于是否還有剩余值。這意味著如果您實現(xiàn)迭代器協(xié)議,您可以創(chuàng)建自己的迭代器對象。
JavaScript 的也有一些內(nèi)置的迭代器像String, Array 和 Map 等。您可以使用for... of 循環(huán)來遍歷它們。與常規(guī)for循環(huán)相比,這將更簡潔且不易出錯 。
let people = ["Andrew", "Adam", "James", "Jack"];
let people_count = people.length;
for(let i = 0; i < people_count; i++) {
console.log(people[i]);
}
/*
Andrew
Adam
James
Jack
*/
for(person of people) {
console.log(person);
}
/*
Andrew
Adam
James
Jack
*/
使用 for...of 循環(huán),我們不必跟蹤數(shù)組的總長度或當前索引。這可以在創(chuàng)建嵌套循環(huán)時降低代碼復(fù)雜性。
23. async 和 await
您可以使用 async 關(guān)鍵字來創(chuàng)建始終顯式或隱式返回Promise的異步函數(shù)。您創(chuàng)建的異步函數(shù)可以await 通過停止執(zhí)行直到解決返回的Promise來利用 關(guān)鍵字。async 函數(shù)外的代碼 將繼續(xù)正常執(zhí)行。
在上面的示例中, "Hello Andrew" 兩秒后記錄,而所有其他 hello 立即記錄。對delayed_hello() 函數(shù)的調(diào)用會 "Hello Adam" 立即記錄 ,但要等待Promise解析才能記錄 "Hello Andrew"。
就是這樣,伙計們 所以你有它; JavaScript 初學者的 23個基本技巧。謝謝閱讀
寫在最后:
如果你感覺寫得不錯,幫我點個[ 在看、贊、關(guān)注]吧讓我們一起成為前端架構(gòu)師! 關(guān)注公眾號:全棧修煉,第一時間了解國內(nèi)外前端前沿技術(shù)!
