簡介:web前端教程、實戰項目、電子書等資料,看文末現在寫代碼比以前好多了,代碼的格式都有eslint,prettier,babel(寫新版語法)這些來保證,然而,技術手段再高端都不能解決代碼可讀性(代碼能否被未來的自己和同事看懂) ...轉發+關注,私信小編“資料”免費分享資料給你!
web前端教程、實戰項目、電子書等資料,看文末
現在寫代碼比以前好多了,代碼的格式都有eslint,prettier,babel(寫新版語法)這些來保證,然而,技術手段再高端都不能解決代碼可讀性(代碼能否被未來的自己和同事看懂)的問題,因為這個問題只有人自己才能解決。我們寫代碼要寫到下圖中左邊這樣基本上就功德圓滿了。
一、變量相關
(1)變量數量的定義
NO:濫用變量:
<code>let
kpi
=
4
;
// 定義好了之後再也沒用過
function
example
()
{
var
a
=
1
;
var
b
=
2
;
var
c
=
a
+
b
;
var
d
=
c
+
1
;
var
e
=
d
+
a
;
return
e
;
}/<code>
YES: 數據只使用一次或不使用就無需裝到變量中
<code>let
kpi
=
4
;
// 沒用的就刪除掉,不然過三個月自己都不敢刪,怕是不是那用到了
function
example
()
{
var
a
=
1
;
var
b
=
2
;
return
2a
+
b
+
1
;
}/<code>
(2)變量的命名
NO:自我感覺良好的縮寫
<code>let
fName
=
'jackie'
;
// 看起來命名挺規範,
縮寫,駝峰法都用上,ESlint各種檢測規範的工具都通過,
But,fName是啥?這時候,
你是不是想說What are you 弄啥呢?
let
lName
=
'willen'
;
// 這個問題和上面的一樣/<code>
YES:無需對每個變量都寫註釋,從名字上就看懂
<code>let
firstName
=
'jackie'
;
// 怎麼樣,是不是一目瞭然。少被噴了一次
let
lastName
=
'willen'
;/<code>
(3)特定的變量
NO:無說明的參數
<code>if
(
value
.
length
<
8
)
{
// 為什麼要小於8,8表示啥?
長度,還是位移,還是高度?Oh,my God!!
....
}/<code>
YES:添加變量
<code>const
MAX_INPUT_LENGTH
=
8
;
if
(
value
.
length
<
MAX_INPUT_LENGTH
)
{
// 一目瞭然,不能超過最大輸入長度
....
}/<code>
(4)變量的命名
NO:命名過於囉嗦
<code>let
nameString
;
let
theUsers
;/<code>
YES: 做到簡潔明瞭
<code>let
name
;
let
users
;/<code>
(5)使用說明性的變量(即有意義的變量名)
NO:長代碼不知道啥意思
<code>const
address
=
'One Infinite Loop, Cupertino 95014'
;
const
cityZipCodeRegex
=
/^[^,\\]+[,\\s]+(.+?)s*(d{5})?$/
;
saveCityZipCode
(
address
.
match
(
cityZipCodeRegex
)[
1
],
// 這個公式到底要幹嘛,
對不起,原作者已經離職了。自己看代碼
address
.
match
(
cityZipCodeRegex
)[
2
],
// 這個公式到底要幹嘛,對不起,
原作者已經離職了。自己看代碼
);/<code>
YES:用變量名來解釋長代碼的含義
<code>const
address
=
'One Infinite Loop, Cupertino 95014'
;
const
cityZipCodeRegex
=
/^[^,\\]+[,\\s]+(.+?)s*(d{5})?$/
;
const
[,
city
,
zipCode
]
=
address
.
match
(
cityZipCodeRegex
)
||
[];
saveCityZipCode
(
city
,
zipCode
);/<code>
(6)避免使用太多的全局變量
NO:在不同的文件不停的定義全局變量
<code>name
.
js
window
.
name
=
'a'
;
hello
.
js
window
.
name
=
'b'
;
time
.
js
window
.
name
=
'c'
;
//三個文件的先後加載順序不同,
都會使得window.name的值不同,同時,
你對window.name的修改了都有可能不生效,
因為你不知道你修改過之後別人是不是又在別的說明文件中對其的值重置了。
所以隨著文件的增多,會導致一團亂麻。/<code>
YES:少用或使用替代方案 你可以選擇只用局部變量。通過(){}的方法。
<code>如果你確實用很多的全局變量需要共享,你可以使用
vuex
,
redux
或者你自己參考
flux
模式寫一個也行。/<code>
(7) 變量的賦值。
NO:對於求值獲取的變量,沒有兜底。
<code>const
MIN_NAME_LENGTH
=
8
;
let
lastName
=
fullName
[
1
];
if
(
lastName
.
length
>
MIN_NAME_LENGTH
)
{
// 這樣你就給你的代碼成功的埋了一個坑,你有考慮過如果fullName = ['jackie']這樣的情況嗎?這樣程序一跑起來就爆炸。要不你試試。
....
}/<code>
YES:對於求值變量,做好兜底。
<code>const
MIN_NAME_LENGTH
=
8
;
let
lastName
=
fullName
[
1
]
||
''
;
// 做好兜底,fullName[1]中取不到的時候,
不至於賦值個undefined,至少還有個空字符,從根本上講,
lastName的變量類型還是String,String原型鏈上的特性都能使用,
不會報錯。不會變成undefined。
if
(
lastName
.
length
>
MIN_NAME_LENGTH
)
{
....
}
其實在項目中有很多求值變量,對於每個求值變量都需要做好兜底。
let
propertyValue
=
Object
.
attr
||
0
;
// 因為Object.attr有可能為空,所以需要兜底。
但是,賦值變量就不需要兜底了。
let
a
=
2
;
// 因為有底了,所以不要兜著。
let
myName
=
'Tiny'
;
// 因為有底了,所以不要兜著。/<code>
二、函數相關
(1)函數命名
NO:從命名無法知道返回值類型
<code>function
showFriendsList
()
{....}
// 現在問,
你知道這個返回的是一個數組,還是一個對象,還是true or false。
你能答的上來否?你能答得上來我請你吃松鶴樓的滿漢全席還請你不要當真。/<code>
Yes: 對於返回true or false的函數,最好以should/is/can/has開頭
<code>function
shouldShowFriendsList
()
{...}
function
isEmpty
()
{...}
function
canCreateDocuments
()
{...}
function
hasLicense
()
{...}/<code>
(2) 功能函數最好為純函數
NO: 不要讓功能函數的輸出變化無常。
<code>function
plusAbc
(
a
,
b
,
c
)
{
// 這個函數的輸出將變化無常,
因為api返回的值一旦改變,同樣輸入函數的a,b,c的值,
但函數返回的結果卻不一定相同。
var
c
=
fetch
(
'../api'
);
return
a
+
b
+
c
;
}/<code>
YES:功能函數使用純函數,輸入一致,輸出結果永遠唯一
<code>function
plusAbc
(
a
,
b
,
c
)
{
// 同樣輸入函數的a,b,c的值,
但函數返回的結果永遠相同。
return
a
+
b
+
c
;
}/<code>
(3)函數傳參
NO:傳參無說明
<code>page
.
getSVG
(
api
,
true
,
false
);
// true和false啥意思,一目不了然/<code>
YES: 傳參有說明
<code>page
.
getSVG
({
imageApi
:
api
,
includePageBackground
:
true
,
// 一目瞭然,
知道這些true和false是啥意思
compress
:
false
,
})/<code>
(4)動作函數要以動詞開頭
NO: 無法辨別函數意圖
<code>function
emlU
(
user
)
{
....
}/<code>
YES:動詞開頭,函數意圖就很明顯
<code>function
sendEmailToUser
(
user
)
{
....
}/<code>
(5)一個函數完成一個獨立的功能,不要一個函數混雜多個功能
這是軟件工程中最重要的一條規則,當函數需要做更多的事情時,它們將會更難進行編寫、測試、理解和組合。當你能將一個函數抽離出只完成一個動作,他們將能夠很容易的進行重構並且你的代碼將會更容易閱讀。如果你嚴格遵守本條規則,你將會領先於許多開發者。
NO:函數功能混亂,一個函數包含多個功能。最後就像能以一當百的老師傅一樣,被亂拳打死(亂拳(功能複雜函數)打死老師傅(老程序員))
<code>function
sendEmailToClients
(
clients
)
{
clients
.
forEach
(
client
=>
{
const
clientRecord
=
database
.
lookup
(
client
)
if
(
clientRecord
.
isActive
())
{
(
client
)
}
})
}/<code>
YES: 功能拆解,
<code>function
sendEmailToActiveClients
(
clients
)
{
//各個擊破,易於維護和複用
clients
.
filter
(
isActiveClient
).
forEach
(
)
}
function
isActiveClient
(
client
)
{
const
clientRecord
=
database
.
lookup
(
client
)
return
clientRecord
.
isActive
()
}/<code>
(6)優先使用函數式編程
NO: 使用for循環編程
<code>for
(
i
=
1
;
i
<=
10
;
i
++)
{
// 一看到for循環讓人頓生不想看的情愫
a
[
i
]
=
a
[
i
]
+
1
;
}/<code>
YES:使用函數式編程
<code>let
b
=
a
.
map
(
item
=>
++
item
)
// 怎麼樣,是不是很好理解,
就是把a的值每項加一賦值給b就可以了。
現在在javascript中幾乎所有的for循環都
可以被map,filter,find,some,any,forEach等函數式編程取代。/<code>
(7) 函數中過多的採用if else ..
No: if else過多
<code>if
(
a
===
1
)
{
...
}
else
if
(
a
===
2
)
{
...
}
else
if
(
a
===
3
)
{
...
}
else
{
...
}/<code>
YES: 可以使用switch替代或用數組替代
<code>switch
(
a
)
{
case
1
:
....
case
2
:
....
case
3
:
....
default
:
....
}
Or
let
handler
=
{
1
:
()
=>
{....},
2
:
()
=>
{....}.
3
:
()
=>
{....},
default
:
()
=>
{....}
}
handler
[
a
]()
||
handler
[
'default'
]()/<code>
三、儘量使用ES6,有可以能的話ES7中新語法(只羅列最常用的新語法,說實話,有些新語法不怎麼常用)
(1)儘量使用箭頭函數
NO:採用傳統函數
<code>function
foo
()
{
// code
}/<code>
YES:使用箭頭函數
<code>let
foo
=
()
=>
{
// code
}/<code>
(2)連接字符串
NO:採用傳統+號
<code>var
message
=
'Hello '
+
name
+
', it's '
+
time
+
' now'/<code>
YES:採用模板字符
<code>var
message
=
`Hello ${name}, it's ${time} now`/<code>
(3) 使用解構賦值
NO:使用傳統賦值:
<code>var
data
=
{
name
:
'dys'
,
age
:
1
};
var
name
=
data
.
name
;
var
age
=
data
.
age
;
var
fullName
=
[
'jackie'
,
'willen'
];
var
firstName
=
fullName
[
0
];
var
lastName
=
fullName
[
1
];/<code>
YES:使用結構賦值:
<code>const
data
=
{
name
:
'dys'
,
age
:
1
};
const
{
name
,
age
}
=
data
;
// 怎麼樣,是不是簡單明瞭
var
fullName
=
[
'jackie'
,
'willen'
];
const
[
firstName
,
lastName
]
=
fullName
;/<code>
(4) 儘量使用類class
NO: 採用傳統的函數原型鏈實現繼承
<code>典型的
ES5
的類(
function
)在繼承、構造和方法定義方面可讀性較差,
當需要繼承時,優先選用
class
。代碼太多,就省略了。/<code>
YES:採用ES6類實現繼承
<code>class
Animal
{
constructor
(
age
)
{
this
.
age
=
age
}
move
()
{
/* ... */
}
}
class
Mammal
extends
Animal
{
constructor
(
age
,
furColor
)
{
super
(
age
)
this
.
furColor
=
furColor
}
liveBirth
()
{
/* ... */
}
}
class
Human
extends
Mammal
{
constructor
(
age
,
furColor
,
languageSpoken
)
{
super
(
age
,
furColor
)
this
.
languageSpoken
=
languageSpoken
}
speak
()
{
/* ... */
}
}/<code>
先寫到這了,這是目前為止發現的問題,這篇文章中並沒有完全覆蓋到常見的寫代碼的不好的習慣,所以你如果覺的有需要補充的,都可以在文章下方評論,或者直接到我的Github的這篇文章中評論。對於有用的,都將補充到我的掘金和Github中去。同時,你如果覺的文章寫得還可以,Please在我的Github中送上你寶貴的Star,你的Star是我繼續寫文章最大的動力。
<code>注:除了上述這些人為習慣之外,就像前面提到的,對於機械性的,
你可以使用
Babel
、
Eslint
、
Prettier
這些工具來保證代碼的格式一致。/<code>
學習前端的小夥伴注意了,最近整理了一份web前端教程、實戰項目、電子書等資料,回饋給大家,需要的關注並轉發此文,後臺私信回覆 (資料)即可領取
閱讀更多 s初悸l 的文章