有時候,區塊程式碼產生器需要多次參照其內部區塊的程式碼。
舉例來說,如果您有一個區塊會輸出清單的最後一個元素,就必須多次存取清單程式碼:
// Incorrect block-code generator.
javascriptGenerator.forBlock['print_last_element'] = function(block, generator) {
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
// listCode gets referenced twice.
return `print(${listCode}[${listCode}.length - 1]);\n`;
}
但如果內部區塊的程式碼產生的值不一致,或有副作用,則可能會造成問題。舉例來說,如果內部程式碼實際上是函式呼叫,這個特定程式碼最後可能會超出範圍條件:
print(randomList()[randomList().length - 1]);
指派至臨時變數可讓您確保內部區塊的程式碼只評估一次。
臨時變數
臨時變數會儲存內部區塊的程式碼字串值,讓該程式碼僅「評估」一次,之後可以多次參照該值。
import {javascriptGenerator, Order} from 'blockly/javascript';
// Correct block-code generator.
javascriptGenerator.forBlock['print_last_element'] = function(block, generator) {
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
const listVar = generator.nameDB_.getDistinctName(
'temp_list', Blockly.names.NameType.VARIABLE);
// listCode only gets evaluated once.
const code = `var ${listVar} = ${listCode};\n`;
return `print(${listVar}[${listVar}.length - 1]);\n`;
}
getDistinctName
呼叫會使用您想要的變數名稱,並傳回不會與任何使用者定義的變數相衝突的名稱。
減少多餘程式碼
臨時變數的缺點是,如果內部區塊的程式碼是值,而不是函式或運算式,則得到多餘的程式碼:
// Assigning to temp_list is unnecessary.
var temp_list = foo;
print(temp_list[temp_list.length - 1]);
如要產生更簡潔的程式碼,您可以檢查內部區塊的程式碼是否為值,且只加入臨時變數 (如果沒有)。
if (listCode.match(/^\w+$/)) {
const code = `print(${listCode}[${listCode}.length - 1]);\n`;
} else {
const listVar = generator.nameDB_.getDistinctName(
'temp_list', Blockly.names.NameType.VARIABLE);
const code = `var ${listVar} = ${listCode};\n`;
code += `print(${listVar}[${listVar}.length - 1]);\n`;
}