Иногда вашему генератору блочного кода необходимо несколько раз ссылаться на код своего внутреннего блока.
Например, если у вас есть блок, который печатает последний элемент списка, вам необходимо получить доступ к коду списка несколько раз:
// 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`;
}