1、函式要短小,一個函式只做一件事
如果函式做了較多的事情,它就難以組合、測驗和推測,同時讓函式只做一件事情的時候,它們就很容易重構,
// Bad
function
showStudent(ssn){
const
student = db.
get
(ssn);
if
(student !==
null
){
document.querySelector(
`#${elementId}`
).innerHTML =
`${student.ssn},
${student.firstName},
${student.lastName}`
}
else
{
thrownew
Error
(
'student not found'
)
}
}
showStudent(
'444-44-4444'
)
// Good
function
findStudent(db,id){
const
student = db.
get
(id);
if
(student ===
null
){
thrownew
Error
(
'student not found'
);
}
};
function
getStudentInfo(student){
return
`${student.ssn},${student.firstName},${student.lastName}`
};
function
showStudentInfo(elementId,info){
document.querySelector(elementId).innerHTML = info;
}
function
showStudent(ssn){
const
student = findStudent(ssn);
let
studentInfo = getStudentInfo(student);
showStudentInfo(elementId,studentInfo);
}
只是做了些許的改進,但已開始展現出很多的優勢:undefined
2、每個函式一個抽象層級
函式中混雜不同的抽象層級,往往讓人迷惑,讀者可能無法判斷某個運算式是基礎概念還是細節,更惡劣的是,就像破損的窗戶,一旦細節和基礎概念混雜,更多的細節就會在函式中糾結起來,理解抽象層次請參考:抽象層次
// Bad
function
parseBetterJSAlternative(code) {
let
REGEXES = [
// ...
];
let
statements = code.split(
' '
);
let
tokens;
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...
})
});
let
ast;
tokens.forEach((token) => {
// lex...
});
ast.forEach((node) => {
// parse...
})
}
// Good
function
tokenize(code) {
let
REGEXES = [
// ...
];
let
statements = code.split(
' '
);
let
tokens;
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...
})
});
return
tokens;
}
function
lexer(tokens) {
let
ast;
tokens.forEach((token) => {
// lex...
});
return
ast;
}
function
parseBetterJSAlternative(code) {
let
tokens = tokenize(code);
let
ast = lexer(tokens);
ast.forEach((node) => {
// parse...
})
}
3、使用描述性的名稱
函式越短小,功能越集中,就越便于取個好名字,長而具有描述性的名稱,要比短而令人費解的名稱好,長而具有描述性的名稱,要比描述性的長注釋好,使用某種命名約定,讓函式名稱中的多個單詞容易閱讀,然后使用這些單詞給函式取個能說明其功能的名稱,
// Bad
function
dateAdd(date, month) {
// ...
}
let
date =
new
Date
();
// 很難從函式名了解到加了什么
dateAdd(date,
1
);
function
write(name){
// ...
}
function
assertEqual(a,b){
// ...
}
// Good
function
dateAddMonth(date, month) {
// ...
}
let
date =
new
Date
();
dateAddMonth(date,
1
);
// 告訴我們 name 是一個 field
function
writeField(name){
// ...
}
// 能更好的解釋引數的順序和意圖
function
assertExpectedEqualActual(expected,actual){
// ...
}
4、函式引數
最理想的引數數量是零,其次是一(單引數函式),再次是二(雙引數函式),應盡量避免三(三引數函式),有足夠的理由才能使用三個以上引數,如果函式需要三個以上引數,就說明其中一些引數應該放在一個物件中了,引數越多,函式越不容易理解,同時撰寫能確保引數的各種組合運行正常的測驗用例越困難,
5、避免副作用
如果一個函式不是獲取一個輸入的值并回傳其它值,它就有可能產生副作用,這些副作用可能是寫入檔案、修改一些全域變數、螢屏列印或者日志記錄、查詢HTML檔案、瀏覽器的cookie或訪問資料庫,無論哪種情況,都具有破壞性,會導致古怪的時序性耦合及順序依賴,現在你確實需要在程式中有副作用,像前面提到的那樣,你可能需要寫入檔案,現在你需要做的事情是搞清楚在哪里集中完成這件事情,不要使用幾個函式或類來完成寫入某個特定檔案的作業,采用一個,就一個服務來完成,
// Bad
// 下面的函式使用了全域變數,
// 如果有另一個函式在使用 name,現在可能會因為 name 變成了陣列而不能正常運行,
var
name =
'Ryan McDermott'
;
function
splitIntoFirstAndLastName() {
name = name.split(
' '
);
}
splitIntoFirstAndLastName();
console.log(name);
// ['Ryan', 'McDermott'];
// Good
function
splitIntoFirstAndLastName(name) {
return
name.split(
' '
);
}
var
name =
'Ryan McDermott'
var
newName = splitIntoFirstAndLastName(name);
console.log(name);
// 'Ryan McDermott';
console.log(newName);
// ['Ryan', 'McDermott'];
6、洗掉重復代碼
重復代碼意味著你要修改某些邏輯的時候要修改不止一個地方的代碼,
// Bad
function
showDeveloperList(developers) {
developers.forEach(developers => {
var
expectedSalary = developer.calculateExpectedSalary();
var
experience = developer.getExperience();
var
githubLink = developer.getGithubLink();
var
data = {
expectedSalary: expectedSalary,
experience: experience,
githubLink: githubLink
};
render(data);
});
}
function
showManagerList(managers) {
managers.forEach(manager => {
var
expectedSalary = manager.calculateExpectedSalary();
var
experience = manager.getExperience();
var
portfolio = manager.getMBAProjects();
var
data = {
expectedSalary: expectedSalary,
experience: experience,
portfolio: portfolio
};
render(data);
});
}
// Good
function
showList(employees) {
employees.forEach(employee => {
var
expectedSalary = employee.calculateExpectedSalary();
var
experience = employee.getExperience();
var
portfolio;
if
(employee.type ===
'manager'
) {
portfolio = employee.getMBAProjects();
}
else
{
portfolio = employee.getGithubLink();
}
var
data = {
expectedSalary: expectedSalary,
experience: experience,
portfolio: portfolio
};
render(data);
});
}
7、使用更優雅寫法
1、使用默認引數代替短路運算式
// Bad
function
writeForumComment(subject, body) {
subject = subject ||
'No Subject'
;
body = body ||
'No text'
;
}
// Good
function
writeForumComment(subject =
'No subject'
, body =
'No text'
) {
...
}
2、用 Object.assign 設定默認物件
// Bad
const
menuConfig = {
title:
null
,
body:
'Bar'
,
buttonText:
null
,
cancellable:
true
}
function
createMenu(config) {
config.title = config.title ||
'Foo'
config.body = config.body ||
'Bar'
config.buttonText = config.buttonText ||
'Baz'
config.cancellable = config.cancellable ===
undefined
? config.cancellable :
true
;
}
createMenu(menuConfig);
// Good
const
menuConfig = {
title:
'Order'
,
// User did not include 'body' key
buttonText:
'Send'
,
cancellable:
true
}
function
createMenu(config) {
config =
Object
.assign({
title:
'Foo'
,
body:
'Bar'
,
buttonText:
'Baz'
,
cancellable:
true
}, config);
// 現在 config 等于: {title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true}
// ...
}
createMenu(menuConfig);
3、喜歡上命令式編程之上的函式式編程
// Bad
const
programmerOutput = [
{
name:
'Uncle Bobby'
,
linesOfCode:
500
}, {
name:
'Suzie Q'
,
linesOfCode:
1500
}, {
name:
'Jimmy Gosling'
,
linesOfCode:
150
}, {
name:
'Gracie Hopper'
,
linesOfCode:
1000
}
];
var
totalOutput =
0
;
for
(
var
i =
0
; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
// Good
const
programmerOutput = [
{
name:
'Uncle Bobby'
,
linesOfCode:
500
}, {
name:
'Suzie Q'
,
linesOfCode:
1500
}, {
name:
'Jimmy Gosling'
,
linesOfCode:
150
}, {
name:
'Gracie Hopper'
,
linesOfCode:
1000
}
];
var
totalOutput = programmerOutput
.map((programmer) => programmer.linesOfCode)
.reduce((acc, linesOfCode) => acc + linesOfCode,
0
);
8、不要把標記用作函式引數
標記告訴你的用戶這個函式做的事情不止一件,但是函式應該只做一件事,如果你的函式中會根據某個布爾引數產生不同的分支,那就拆分這個函式,
// Bad
function
createFile(name, temp) {
if
(temp) {
fs.create(
'./temp/'
+ name);
}
else
{
fs.create(name);
}
}
// Good
function
createTempFile(name) {
fs.create(
'./temp/'
+ name);
}
function
createFile(name) {
fs.create(name);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/259247.html
標籤:其他
上一篇:HTTP回應頭資訊介紹
