如果你常在試算表寫自動化腳本,八成遇過這一幕:只想改一格,結果整塊區域都被蓋成同一個值。兇手通常就是 setValue()——它很直覺,卻也很容易被誤用。
本篇文章會用最貼近實務的方式,把 setValue() 從零到一講清楚:怎麼選到正確的 Range、什麼時候該用它、什麼時候要改成 setValues(),還有日期、時間、公式、核取方塊這些「麻煩值」的正確寫法。
中間會穿插小範例與排雷清單,像是時區導致的時間戳跑掉、格式只改外觀不改內容、在迴圈裡狂呼叫導致變慢等狀況。看完你會知道:要單點寫值就乾脆用 setValue(),要批次回寫就一次丟陣列,同時把效能與穩定度顧好。希望本篇文章能夠幫助到需要的您。
目錄
{tocify} $title={目錄}
setValue() 是什麼?
setValue(value) 會把「一個值」寫進 你選到的整個 Range。如果那個 Range 包含多個儲存格,所有儲存格都會被寫成同一個值。
與 setValues() 的差異
setValue(value):一個值 → 套用到整個 Range(多格同值)。
setValues(values):二維陣列 → 尺寸必須與 Range 完全一致,常用於批次寫入大量不同值(效能更好)。
實務上,一個 setValues() 幾乎一定比在迴圈裡呼叫很多次 setValue() 快。這點在實戰經驗與社群討論中屢被驗證。
從零開始:最小可用範例
建立腳本與取得工作表
1. 開啟你的 Google 試算表 → 擴充功能 → Apps Script。
2. 新增專案,將預設的 Code.gs 內容替換為下列程式。
function demoSetValue() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet(); // 或 ss.getSheetByName('工作表名稱')
const range = sheet.getRange('A1'); // 指向單一儲存格
range.setValue('Hello setValue'); // 寫入文字
}
Range 可以是 A1 標記、或用列/欄/高/寬指定,兩者都行。
一次寫滿多格、但同一個值
function fillSameValue() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const rng = sh.getRange(1, 1, 5, 5); // A1:E5
rng.setValue('Hello'); // A1:E5 全部變成 "Hello"
}
這個用法官方語意與教學實例都成立:多格 Range 會被同值覆寫。
批次寫入不同值(用 setValues())
function writeMatrix() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const rng = sh.getRange(2, 1, 3, 2); // A2:B4
const data = [
['品項', '數量'],
['鉛筆', 12],
['筆記本', 5],
];
rng.setValues(data);
}
當你要「一格一格都不一樣」時,使用 setValues() 搭配二維陣列,速度與穩定度都更好。
資料型別與格式:把「看起來」跟「實際值」都處理對
日期與時間(最容易踩雷)
在 Apps Script 裡,Date 物件寫進儲存格後,顯示樣式要靠數字格式控制,否則看起來可能不對。
function writeDate() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const cell = sh.getRange('B2');
cell.setValue(new Date()); // 寫入真正的日期值
cell.setNumberFormat('yyyy-mm-dd hh:mm'); // 控制顯示樣式
}
若地區/語系不同(例如表單是美式 MM/DD/YYYY,你卻想要 YYYY-MM-DD),請務必搭配 setNumberFormat()。
看到正確畫面但底層仍是日期物件,這是正確的;別把格式化後的樣式誤認為文字。
直接寫出「時間戳」
function writeTimestamp() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const cell = sh.getRange('C2');
cell.setValue(new Date());
cell.setNumberFormat('yyyy-mm-dd hh:mm:ss');
}
公式:要值還是要公式?
寫入公式:cell.setValue('=SUM(A2:A10)') → 儲存格會持有公式,並顯示計算結果。
寫入計算後的值:先在腳本端算完或貼值,避免後續被資料變動影響。
布林與核取方塊
function writeCheckbox() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const cell = sh.getRange('D2');
// 先把儲存格設為核取方塊(UI 或資料驗證)
cell.insertCheckboxes();
cell.setValue(true); // 勾選
}
效能最佳化:避免「慢到想睡」
什麼時候用 setValue()?
你只改一格或多格同一個值(像是整塊標記「N/A」)。
事件觸發器(onEdit)裡,只需要落一個時間戳或旗標。
什麼時候改用 setValues()?
你在迴圈中對很多儲存格重複
setValue()。把資料先組成二維陣列,一次
setValues()
會快非常多。
示例:把慢速迴圈寫法改成一次寫入
function slowToFast() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const values = [];
for (let r = 0; r < 1000; r++) {
values.push([`Row ${r+1}`, r+1]); // 二維陣列:每列兩欄
}
sh.getRange(2, 1, values.length, values[0].length).setValues(values);
}
實戰情境
情境 A:表單送出後自動補上處理狀態
function markSubmitted(e) {
const sh = SpreadsheetApp.getActive().getSheetByName('Responses');
const lastRow = sh.getLastRow();
sh.getRange(lastRow, 5).setValue('Received'); // 第 5 欄寫入狀態
}
情境 B:根據條件把一塊區域全數標記「N/A」
function markNAIfClosed() {
const sh = SpreadsheetApp.getActive().getActiveSheet();
const status = sh.getRange('A1').getValue();
const block = sh.getRange('B2:D20');
if (status === 'Closed') block.setValue('N/A'); // 多格同值
}
常見錯誤與雷點
1.「我只想改一格,結果整排都被改了」
你選到的其實是整列/整塊 Range;setValue() 自然把同一值寫進整個 Range。先確認 getRange() 的座標或 A1 標記;必要時改用單一儲存格的 Range。
2. 日期顯示怪、或不同地區格式互相打架
資料本體(Date)正確,但顯示格式沒設。請加上 setNumberFormat();若表單/工作表地區不同,請統一地區設定再寫入。
3. 把「樣式」當「值」
setNumberFormat() 只改外觀,不改底層資料型別;若你需要字串(例如要輸出 "2025-10-04"),請在程式端格式化成字串再 setValue()。
4. 在迴圈中大量 setValue() → 變慢
把資料先組成二維陣列,一次 setValues();避免呼叫界面 API 的次數。
5. 多格不同值卻用 setValue()
結果整塊都變同值。要不同值 → 改用 setValues(),而且陣列尺寸要正確對齊 Range。
6. 寫入文字「看起來像日期」卻被自動轉型
想「強制寫成文字」,可以先設定格式為 @,或在字串前加前導單引號 '2025/10/04。
7. 寫入公式但期望固定值
setValue('=...') 會留下公式;若要固定值,請改在腳本端計算後再寫入。
8. 跨時區的時間戳記誤差
使用 new Date() 會以伺服器時區為準;如果有時區需求,請在 Apps Script 端用 Utilities.formatDate() 轉為目標時區的字串再寫入。
9. 一次把同值寫滿整塊的正確用法
這正是 setValue() 的強項;想快速把一大片標記為「N/A」「清空成空字串」都很適合。
10. 多處位置同時寫入不同值
請抓一個覆蓋面足夠的 Range,先 getValues()、在陣列裡改動多個點,再 setValues() 回去。
問題集
Q1:我可不可以對「非連續」區塊一次寫入?
Apps Script Range 代表的是連續區域。非連續寫入得拆成多個 Range 操作,或用「大範圍陣列→內文定位修改→一次 setValues() 回寫」的策略。
Q2:setValue() 真的會把多格都改成同值嗎?
是。你選到多格 Range,它就對那整塊寫同一個值;示例與文檔皆有展示。
Q3:效能到底差多少?
場景不同、資料量不同,但「一口氣回寫陣列」通常顯著更快,這是 Apps Script 社群長年共識與最佳實務。
