碼必須盡可能的清晰和易讀。
這實際上是一種編程藝術 —— 以一種正確并且人們易讀的方式編碼來完成一個復雜的任務。一個良好的代碼風格大大有助于實現這一點。
下面是一個備忘單,其中列出了一些建議的規則(詳情請參閱下文):
現在,讓我們詳細討論一下這些規則和它們的原因吧。
沒有什么規則是“必須”的
沒有什么規則是“刻在石頭上”的。這些是風格偏好,而不是宗教教條。
在大多數的 JavaScript 項目中,花括號以 “Egyptian” 風格(譯注:“egyptian” 風格又稱 K&R 風格 — 代碼段的開括號位于一行的末尾,而不是另起一行的風格)書寫,左花括號與相應的關鍵詞在同一行上 — 而不是新起一行。左括號前還應該有一個空格,如下所示:
if (condition) {
// do this
// ...and that
// ...and that
}
單行構造(如 if (condition) doSomething())也是一個重要的用例。我們是否應該使用花括號?如果是,那么在哪里?
下面是這幾種情況的注釋,你可以自己判斷一下它們的可讀性:
對于很短的代碼,寫成一行是可以接受的:例如 if (cond) return null。但是代碼塊(最后一個示例)通常更具可讀性。
沒有人喜歡讀一長串代碼,最好將代碼分割一下。
例如:
// 回勾引號 ` 允許將字符串拆分為多行
let str = `
ECMA International's TC39 is a group of JavaScript developers,
implementers, academics, and more, collaborating with the community
to maintain and evolve the definition of JavaScript.
`;
對于 if 語句:
if (
id === 123 &&
moonPhase === 'Waning Gibbous' &&
zodiacSign === 'Libra'
) {
letTheSorceryBegin();
}
一行代碼的最大長度應該在團隊層面上達成一致。通常是 80 或 120 個字符。
有兩種類型的縮進:
show(parameters,
aligned, // 5 spaces padding at the left
one,
after,
another
) {
// ...
}
function pow(x, n) {
let result = 1;
// <--
for (let i = 0; i < n; i++) {
result *= x;
}
// <--
return result;
}
插入一個額外的空行有助于使代碼更具可讀性。寫代碼時,不應該出現連續超過 9 行都沒有被垂直分割的代碼。
每一個語句后面都應該有一個分號。即使它可以被跳過。
有一些編程語言的分號確實是可選的,那些語言中也很少使用分號。但是在 JavaScript 中,極少數情況下,換行符有時不會被解釋為分號,這時代碼就容易出錯。更多內容請參閱 代碼結構 一章的內容。
如果你是一個有經驗的 JavaScript 程序員,你可以選擇像 StandardJS 這樣的無分號的代碼風格。否則,最好使用分號以避免可能出現的陷阱。大多數開發人員都應該使用分號。
盡量避免代碼嵌套層級過深。
例如,在循環中,有時候使用 continue 指令以避免額外的嵌套是一個好主意。
例如,不應該像下面這樣添加嵌套的 if 條件:
for (let i = 0; i < 10; i++) {
if (cond) {
... // <- 又一層嵌套
}
}
我們可以這樣寫:
for (let i = 0; i < 10; i++) {
if (!cond) continue;
... // <- 沒有額外的嵌套
} //多用這種風格。
使用 if/else 和 return 也可以做類似的事情。
例如,下面的兩個結構是相同的。
第一個:
function pow(x, n) {
if (n < 0) {
alert("Negative 'n' not supported");
} else {
let result = 1;
for (let i = 0; i < n; i++) {
result *= x;
}
return result;
}
}
第二個:
function pow(x, n) {
if (n < 0) {
alert("Negative 'n' not supported");
return;
}
let result = 1;
for (let i = 0; i < n; i++) {
result *= x;
}
return result;
}
但是第二個更具可讀性,因為 n < 0 這個“特殊情況”在一開始就被處理了。一旦條件通過檢查,代碼執行就可以進入到“主”代碼流,而不需要額外的嵌套。
如果你正在寫幾個“輔助”函數和一些使用它們的代碼,那么有三種方式來組織這些函數。
// function declarations
function createElement() {
...
}
function setHandler(elem) {
...
}
function walkAround() {
...
}
// the code which uses them
let elem = createElement();
setHandler(elem);
walkAround();
// the code which uses the functions
let elem = createElement();
setHandler(elem);
walkAround();
// --- helper functions ---
function createElement() {
...
}
function setHandler(elem) {
...
}
function walkAround() {
...
}
大多數情況下,第二種方式更好。
這是因為閱讀代碼時,我們首先想要知道的是“它做了什么”。如果代碼先行,那么在整個程序的最開始就展示出了這些信息。之后,可能我們就不需要閱讀這些函數了,尤其是它們的名字清晰地展示出了它們的功能的時候。
風格指南包含了“如果編寫”代碼的通用規則,例如:使用哪個引號、用多少空格來縮進、一行代碼最大長度等非常多的細節。
當團隊中的所有成員都使用相同的風格指南時,代碼看起來將是統一的。無論是團隊中誰寫的,都是一樣的風格。
當然,一個團隊可以制定他們自己的風格指南,但是沒必要這樣做?,F在已經有了很多制定好的代碼風格指南可供選擇。
一些受歡迎的選擇:
如果你是一個初學者,你可以從本章中上面的內容開始。然后你可以瀏覽其他風格指南,并選擇一個你最喜歡的。
檢查器(Linters)是可以自動檢查代碼樣式,并提出改進建議的工具。
它們的妙處在于進行代碼風格檢查時,還可以發現一些代碼錯誤,例如變量或函數名中的錯別字。因此,即使你不想堅持某一種特定的代碼風格,我也建議你安裝一個檢查器。
下面是一些最出名的代碼檢查工具:
它們都能夠做好代碼檢查。我使用的是 ESLint。
大多數檢查器都可以與編輯器集成在一起:只需在編輯器中啟用插件并配置代碼風格即可。
例如,要使用 ESLint 你應該這樣做:
下面是一個 .eslintrc 文件的例子:
{
"extends": "eslint:recommended",
"env": {
"browser": true,
"node": true,
"es6": true
},
"rules": {
"no-console": 0,
"indent": 2
}
}
這里的 "extends" 指令表示我們是基于 “eslint:recommended” 的設置項而進行設置的。之后,我們制定我們自己的規則。
你也可以從網上下載風格規則集并進行擴展。有關安裝的更多詳細信息
此外,某些 IDE 有內置的檢查器,這非常方便,但是不像 ESLint 那樣可自定義。
本文描述的(和提到的代碼風格指南中的)所有語法規則,都旨在幫助你提高代碼可讀性。它們都是值得商榷的。
當我們思考如何寫“更好”的代碼的時候,我們應該問自己的問題是:“什么可以讓代碼可讀性更高,更容易被理解?”和“什么可以幫助我們避免錯誤?”這些是我們討論和選擇代碼風格時要牢記的主要原則。
閱讀流行的代碼風格指南,可以幫助你了解有關代碼風格的變化趨勢和最佳實踐的最新想法。
為手機備忘錄,好多人再熟悉不過,有些人用它隨手札記,有些人用它記錄秘密,有些人認為根本用不上。可是,這個小小的備忘錄,你真的了解嗎?你知道它隱藏的那些秘密功能嗎?
1、 速記功能:有個想法,說出來
想隨時隨地記錄您的重要事項或靈光一閃的金點子,只需說出來。
在華為手機主界面,屏幕解鎖狀態下,從屏幕邊緣的速記區域向內滑動。即可打開備忘錄"速記"功能,可以通過語音、文字或照片方式迅速創建筆記或者創建待辦。并且,備忘錄會將語音轉換為文字,并同時記錄語音和文字。
速記gif
設置方法:打開備忘錄,選擇左上角圖標"?"> 設置 > 速記,打開速記開關。在提示界面打開在其他應用上層顯示,并設置入口位置為屏幕左側或屏幕右側。
二、待辦管理:它提醒您,誤不了
情人節那天,因為備忘錄的提醒,我沒有忘記買禮物。
重要事項,卻總擔心忘了,可以讓備忘錄幫你記住。備忘錄支持語音錄入待辦事項,提醒方式有指定時間和指定位置。
*指定位置:當經過設置的目的地有效范圍并超過1分鐘時,鬧鐘會提醒。
操作方法:在全部待辦列表界面輸入待辦事項后,點擊
添加提醒,設置指定時間/智能位置
三、手寫涂鴉:畫出來,更生動
文字表達不清楚,寥寥幾筆的繪畫可能更生動形象,備忘錄也可以變身畫板。
除了速記助手,手寫涂鴉也讓人相見恨晚。打開備忘錄并進入編輯筆記模式。除了語音、文字和圖片三種方式,還可進行涂鴉。無論是文檔注釋還是繪畫創意,都可以肆意書寫。
操作方法:選擇筆記 >
,點擊
,手寫您要記錄的內容。
四、速記分享:一鍵分享,簡單
想把備忘錄里的內容發個朋友圈,可以輕松一鍵分享。
速記的內容保存為筆記后,可以一鍵分享到微博、微信,精彩內容傳遞更便捷。
操作方法:在全部筆記或全部待辦列表界面,打開要分享的備忘錄,點擊
,按屏幕提示完成分享。
五、更貼心:誤刪了,沒關系
1.最近刪除:挽回誤刪事項
一不小心刪掉的筆記和待辦事項,沒關系!可以在"最近刪除"中找到并恢復。多一重保障,多一份安心。
2..多端同步:備忘內容不丟失
支持多設備數據同步,通過華為賬號,隨時隨地查看和編輯你的備忘錄信息。
HUAWEI P30 系列手機上,有AI注入的備忘錄,就像擁有靈魂一般,它所能做的與過去相比,已經不可同日而語,讓我們感受一下這小小的身軀里那些大大的能量吧。
*不同機型對上述功能的支持情況各有差異,請以手機實際為準。
發現更多精彩功能請下滑主屏幕,搜索"玩機技巧"應用
HUAWEI P30 系列新品開售,點擊以下圖片立即擁有!
移動端跳轉鏈接:
PC端跳轉鏈接:https://www.vmall.com/product/10086501288078.html?cid=90002
里有一些我最喜歡的關于編寫更簡潔的 Javascript 代碼的技巧。
使用const或let聲明所有變量。根據經驗,默認情況下使用const,否則如果需要重新分配變量,則使用let。
應避免使用var關鍵字,因為它幾乎不受作用域限制,導致潛在的作用域錯誤,請參閱我的提升指南。
好處:最佳實踐是在創建變量時初始化變量,這樣您和您的團隊就可以確保沒有變量被閑置。
// ? Avoid this
var old = "";
// ? Do this
const immutable = "John";
let counter = 1;
counter++; // counter === 2;
// Declare objects and arrays as const to prevent type change
const user = {firstname: "John", lastname: "Doe"};
const users = ["Mac", "Roe"];
嚴格相等運算符(===)與相等運算符相同,檢查兩個操作數是否相等,并返回布爾結果。但與相等運算符 ( == )不同,嚴格相等運算符(===)始終認為不同類型的操作數是不同的。
好處:在非嚴格相等運算符的情況下,0 為假將錯誤地等于假。
// ? Avoid this
1 == "1"; // true
0 == false; // true
// ? Do this
1 === 1; // true
1 === "1"; // false
0 === false; // false
原始對象與其原始對象完全不同,這使得它們在包裝在對象中時更難以檢查嚴格相等性。
它們基本上是等價的,但不相等。
// ? Avoid this
const stringObject = new String("Charly");
// ? Do this
const stringPrimitive = "Charly";
// Equality check
stringPrimitive === stringObject; // false
new Number(1) === 1; // false
new Boolean(true) === true; // false
對象字面量是一種速記符號,允許您動態定義對象或數組。
從而避免重復,提高可讀性并防止錯誤,因為我們無法推斷其背后的邏輯,我們當前是在初始化變量還是更新它?
// ? Avoid this
const user = new Object(); // {}
user.firstname = "John"; // { firstname: "John" }
user.lastname = "Doe"; // { firstname: "John", lastname: "Doe" }
// ? Do this
const user = {
firstname: "John",
lastname: "Doe"
};
// ? Avoid this
const fruits = new Array(); // []
fruits.push("banana"); // ["banana"]
fruits.push("mango"); // ["banana", "mango"]
// ? Do this
const fruits = ["banana", "mango"];
將字符串放在一起是一件痛苦的事情,尤其是在組合字符串和變量時。
為了使這個過程更簡單,您可以使用模板文字(用反引號標記),它同時接受字符串和變量,只要它被插值(${})包圍即可。
const firstname = "John";
// ? Avoid this
let greeting = "Hello, " + firstname; // Hello, John
// ? Do this
greeting = `Hello, ${firstname}`; // Hello, John
使用分號作為行終止始終是一個好習慣。
如果您忘記了它,則不會收到警告,因為在大多數情況下它將由 JavaScript 解析器插入。但如果沒有它,你怎么知道表達式何時結束呢?
以for循環為例:
// ? Do this
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
您將無法執行以下操作,因為解析器認為它是一個表達式,而實際上它是三個獨立的表達式:
// ? Not this
for (let i = 0 i < numbers.length i++) {
console.log(numbers[i]);
} // Uncaught SyntaxError: Unexpected identifier
我認為在函數中定義太多參數是一種f壞代碼味道。即使參數有默認值或者是可選的,我們還是以這個例子為例:
// ? Avoid this
function avatarUrl(avatar, format = "small", caption = true) {
// Does something
}
avatarUrl(user.avatar, 'thumb', false)
當您使用此函數時,很難知道使用了哪些參數以及如何使用。最后一個參數false在這里代表什么?
不知道,我們必須打開函數定義才能知道。
如果您需要更改參數的順序會發生什么?那么您必須更改所有函數調用。
對于對象來說,順序并不重要:
// ? Do this
function avatarUrl(avatar, options={format: 'small', caption: true}) {
// Does something
}
avatarUrl(user.avatar, {
format: "thumb",
caption: false
})
嵌套條件使代碼難以理解,但您可以通過提前返回來使用保護子句輕松避免它。
保護子句將允許您刪除大部分 else 條件,使您的代碼像簡單的英語一樣可讀。
// ? Avoid this
function doSomething() {
if (user) {
if (user.role === "ADMIN") {
return 'Administrator';
} else {
return 'User';
}
} else {
return 'Anonymous';
}
}
// ? Do this
function doSomething() {
if (!user) return 'Anonymous'
if (user.role === "ADMIN") return 'Administrator'
return 'User'
}
Javascript 在Array、Object、String上提供了很多內置函數。
找到并學習它們,以充分發揮堆棧的威力。
// ? Avoid this
const users = [
{
username: "JohnDoe",
admin: false
},
{
username: "Todd",
admin: true
},
];
const admins = [];
function getAdmins() {
users.forEach((user) => {
if (user.admin) admins.push(user)
})
return admins
}
// ? Do this
function getAdmins() {
return users.filter((user) => user.admin)
}
讓我們假設,我們大多數人都不善于注意到差異,我們可能需要幾秒鐘才能注意到邏輯上的 not (!)。
讓我們看這個例子:
const users = [
{
username: "JohnDoe",
admin: false
enabled: true
},
{
username: "Todd",
admin: true
enabled: true
},
];
// ? Avoid this
const members = users.filter(u => u.enabled).map(u => !u.admin)
const admins = users.filter(u => u.enabled).map(u => u.admin)
// ? Do this
const enabledUsers = users.filter(u => u.enabled)
const members = enabledUsers.map(u => !u.admin)
const admins = enabledUsers.map(u => u.admin)
成員和管理員分配的區別僅在于邏輯非 (!),如果您需要更改一項分配,那么您還需要更改另一項分配。
另一個例子,不要使用幻數。使用顯式變量代替:
// ? Avoid this
function price_with_taxes(price) {
return price * 1.2
}
// ? Do this
const taxRate = 1.2
function price_with_taxes(price) {
return price * taxRate
}
無論您將“e”寫為“event”,還是將“t”寫為“ticket”,都不會提高您的工作效率,但會降低可讀性并降低即時理解能力。
// ? Avoid this
function someFunction() {
events.forEach(e => {
e.tickets.forEach(t => {
`${e.name} for ${t.full_name}`
})
})
}
// ? Do this
function someFunction() {
events.forEach(event => {
event.tickets.forEach(ticket => {
`${event.name} for ${ticket.full_name}`
})
})
}
在這里你不必猜測 e 和 t 代表什么,你只需閱讀即可。
編碼非常復雜,額外的復雜性足以讓您感到臃腫。這也適用于變量、類、方法......
但也有少數例外,在 for 循環中使用廣泛使用的縮寫(如 i)是可以的。
條件就像大腦的備忘錄,因為您需要在逐步執行每一行代碼時記住它們,以便了解發生了什么。
幸運的是,由于我最喜歡的 ES6 操作符可選鏈接,其中大多數都可以得到簡化。
// ? Avoid this
function doSomething(params) {
if (params && params.filter) return 'Foo'
return 'Bar'
}
// ? Do this
function doSomething(params) {
if (params?.filter) return 'Foo'
return 'Bar'
}
我不了解你,但每次我看到邏輯不(!)時,我的大腦都會暫停一秒鐘,對我來說,讀到這樣的內容感覺更自然:
如果用戶是管理員那么我們就這樣做
而不是:
如果用戶不是管理員,那么我們就會這樣做。
// ? Avoid this
function doSomething(user) {
if (!user || !user.admin) {
// Case where no user or not admin
} else {
// Case where user and user is admin
}
}
// ? Do this
function doSomething(user) {
if (user && user.admin) {
// Case where user and user is admin
} else {
// Case where no user or not admin
}
}
使用for...of語句代替經典的for 循環就是 JavaScript 的一項改進。
這個語法是 ES6 引入的,它包含一個內置的迭代器,這樣你就不必定義自己的變量,將其遞增直到某個長度值:
let users = ["Fedor Emelianenko", "Cyril Gane", "Conor McGregor"];
// ? Avoid this
// This avoids length behind reavaluated at every iteration
let usersCount = users.length;
for (let i = 0; i < usersCount; i++) {
console.log(users[i]);
}
// ? Do this
for(let user of users) {
console.log(users);
}
請注意它的可讀性有多強!而且您不必關心所有這些 (let i = 0; i < usersCount; i++) 笨拙的邏輯,盡管您可能需要它用于某些特定的用例,例如不規則的間隔。
永遠記住,您正在與其他開發人員以及未來的自己一起編寫代碼。您不想制造比編寫代碼要解決的問題更多的問題。
不要編寫代碼來炫耀你的技能,編寫每個人都可以理解和調試的代碼。
如果您有更多提示,我很樂意在評論中向您學習!
把事情簡單化!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。