有时,您的块代码生成器需要多次引用其内部块的代码。
例如,如果您有一个输出列表最后一个元素的代码块,则需要多次访问列表代码:
// 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`;
}