咦?我們都寫完了,為什麼還不進入下一個專題呢?
嘖嘖,這你就不懂了!身為一個工程師,能動,只是交件標準。但是你後續如果還要維護,那麼你寫的這份爛 code 會在未來搞死你!
真心不騙!
不說別的,其實我寫這個系列時,我已經用了這個東東大概有 2 個月了,但是當我回頭整理時,驚為天人!
心中真是充滿了三字經…
所以我特別加了一個部分是要來「優化」你的程式碼。
一方面,你可以在後續更好維護;另一方面,你在之後如果要擴增東西,也比較好處理!
但是在優化之前,我們先來解決一個 Bug!
不知道大家有沒有發現,這支程式,有一個重大的 Bug 呢?
這樣就糟糕了!如果不小心把勾勾拿掉時,使用者不就會又收到重複信件,然後引發一連串你要「客服」的問題…
所以為了不要讓未來的我們難過,我們這邊必須要額外加上一個判斷式:
function onEditTrigger() {
const e = {
range: SpreadsheetApp.getActiveRange()
};
if (e.range.isChecked()) {
const theSheet = e.range.getSheet();
const theRowIndex = e.range.getRow();
const theColIndex = e.range.getColumn();
const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
const theData = {};
theData.email = thisRange.getCell(1, 2).getValue();
theData.shoolId = thisRange.getCell(1,3).getValue();
theData.class = thisRange.getCell(1,4).getValue();
theData.name = thisRange.getCell(1,5).getValue();
console.log(theData);
MailApp.sendEmail({
to: theData.email, // 這邊我們直接把取得的 email 帶入
subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
body: `親愛的同學 ${theData.name} 你好
你的密碼已經修改為「我愛兔兔教」,
請務必記好你的新密碼!
`
});
console.log(`Email已經寄出至 ${theData.email}`);
} else {
console.log(`取消勾選`);
}
}
我們藉由判斷該格是否已經被勾選成為 checked 狀態來決定我們是不是要發信。
弄完之後我們回頭去驗證一下:

我們把勾勾拿掉,然後去看結果:

恩!果然不會寄信了!
但是一定有人會突發奇想:如果是修改到其他欄位呢?
我們直接來實驗吧!


果然不用擔心,因為其他欄位不是 CheckBox ,所以不存在被勾選起來的問題,因此永遠都會是 false!
這邊也附上 Docs 的部分讓你好查詢相關細節: Class Range
結束了 Debug ,我們來談談其他優化的部分。
優化其實不只是將程式碼結構、速度進行優化,同時也包含了使用介面、使用體驗等等。
介面,我們是不用想了啦,就是那個試算表,但是我們可以調整程式碼結構以及使用體驗的部分!
你會問:速度呢?
這個我們先不管…
首先是程式碼結構,我們把 MailApp.sendEmail() 直接寫在 onEditTrigger() 中其實看似沒問題,但是當我們要額外擴充功能時,例如:針對每一個系統要發不同內容的信件,就會出現問題。
因此我們要修改一下,把 MailApp.sendEmail() 這個功能提取出來另外用一個函式來包裝:
function onEditTrigger() {
const e = {
range: SpreadsheetApp.getActiveRange()
};
if (e.range.isChecked()) {
const theSheet = e.range.getSheet();
const theRowIndex = e.range.getRow();
const theColIndex = e.range.getColumn();
const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
const theData = {};
theData.email = thisRange.getCell(1, 2).getValue();
theData.shoolId = thisRange.getCell(1,3).getValue();
theData.class = thisRange.getCell(1,4).getValue();
theData.name = thisRange.getCell(1,5).getValue();
console.log(theData);
- MailApp.sendEmail({
- to: theData.email, // 這邊我們直接把取得的 email 帶入
- subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
- body: `親愛的同學 ${theData.name} 你好
- 你的密碼已經修改為「我愛兔兔教」,
- 請務必記好你的新密碼!
- `
- });
+ sendMail(theData.email, theData.name)
console.log(`Email已經寄出至 ${theData.email}`);
} else {
console.log(`取消勾選`);
}
}
+function sendMail(email, name) {
+ MailApp.sendEmail({
+ to: email,
+ subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
+ body: `親愛的同學 ${name} 你好
+ 你的密碼已經修改為「我愛兔兔教」,
+ 請務必記好你的新密碼!
+ `
+ });
+}
不知道有沒有人注意到,之前寫過的
sendMail()函式這邊可以拿出來用 ???
如果你還沒刪掉,那就拿出來用一用吧!
甚至,我們直接要求傳遞進 sendMail() 函式參數為 Object 型態,再用解構賦值 (註一) 的方式得到需要的內容。
這樣的好處是我們需要什麼內容,都不用再去更動到 onEditTrigger() 中的程式碼,只要去修改 sendMail() 中的參數就可以把功能進行修整了!
當然啦,這有沒有符合 Function Programming 的原則,那就是另外一回事了!
如果你想了解更多,你可以參考註二
總之,藉由這樣的方式我們把 MailApp.sendMail() 這件事情拆出來,在後續的程式碼維護上會更佳的容易!
接下來來到了體驗的優化。
就請你想想看,如果今天你申請了三種不同的系統,但是你都收到同一種信件,這樣合理嗎?
當然不合理啊!
所以我們必須要在寄信時,順便判斷他究竟是哪一個系統,來決定我需要寄出哪一封信。
這邊,我決定跟著上面的步伐,將這個「選擇寄出信件內容」的功能額外拆分出來,獨立成一個 Function:
function selectMailContent(name, system) {
return `親愛的同學 ${name} 你好
你申請了 ${system} 的密碼重設,
系統管理員已經將您的密碼重新設為 「${system === "A 系統"
? "我愛兔兔教"
: system === "B 系統" ? "兔兔叫好聽"
: "這是兔兔教你知道的"
}」
請務必記好你的新密碼!
`;
}
這邊我使用了「三元運算子」
(註三)來決定我要發出去什麼內容
接著將我的程式碼替換進去:
function onEditTrigger() {
const e = {
range: SpreadsheetApp.getActiveRange()
};
if (e.range.isChecked()) {
const theSheet = e.range.getSheet();
const theRowIndex = e.range.getRow();
const theColIndex = e.range.getColumn();
const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
const theData = {};
theData.email = thisRange.getCell(1, 2).getValue();
theData.shoolId = thisRange.getCell(1,3).getValue();
theData.class = thisRange.getCell(1,4).getValue();
theData.name = thisRange.getCell(1,5).getValue();
+ theData.name = thisRange.getCell(1,6).getValue();
console.log(theData);
sendMail(theData)
console.log(`Email已經寄出至 ${theData.email}`);
} else {
console.log(`取消勾選`);
}
}
-function sendMail({email, name}) {
+function sendMail({email, name, system}){
MailApp.sendEmail({
to: email,
subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
- body: `親愛的同學 ${name} 你好
- 你的密碼已經修改為「我愛兔兔教」,
- 請務必記好你的新密碼!
- `
+ body: selectMailContent(name, system)
});
}
function selectMailContent(name, system) {
return `親愛的同學 ${name} 你好
你申請了 ${system} 的密碼重設,
系統管理員已經將您的密碼重新設為 「${system === "A 系統"
? "我愛兔兔教"
: system === "B 系統" ? "兔兔叫好聽"
: "這是兔兔教你知道的"
}」
請務必記好你的新密碼!
`;
}
接下來去試驗一下:



成功~
今天的教學就到這裡囉~
我們成功地完成了一個簡單的勾選寄信系統!明天就要來寫新的專題啦!
有沒有興奮啊?(終於脫離這個奇妙的輪迴了…)
我知道大家可能前面的作業都還沒做,今天先出個延伸題請大家去想一想喔~
明天見囉,掰掰!

學生:話說回來,我們不是工程師,可不可以原本那樣寫就好?
我:只要解決問題的人,就都是工程師!所以當然還是得好好優化一下自己的程式碼啊?
學生:但是…能動就好不是嗎?這樣很麻煩耶!
我:說的也是啦…話說這次的成績,「能補考就好」對吧?加減給個 59 分好了…
學生:老師,我覺得優化是非常重要的,我馬上去進行!(溜走)
註一:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment