语句会阻止缓存参数

有时,您的块代码生成器需要多次引用其内部块的代码。

例如,如果您有一个输出列表最后一个元素的代码块,则需要多次访问列表代码:

// 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`;
}