場合によっては、ブロックコード ジェネレータは内部のコードを参照し、 複数回ブロックされます。
たとえば、リストの最後の要素を出力するブロックがある場合、 リストコードに複数回アクセスする必要がある場合:
// 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]);
一時変数に代入すると、内部ブロックのコードが 評価するのは 1 回だけです。
一時変数
一時変数には、内部ブロックのコード文字列の値が格納されるため、 コードが評価されるのは 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`;
}