Değer blokları, ifadelere karşılık gelir. Bir değer bloğunu iç blok olarak kullandığınızda, oluşturduğu ifadeyi bloğunuzun kodunda birden fazla kez kullanmanız gerekebilir. Örneğin, bir listenin son öğesini alan bir blok, listeyi oluşturan ifadeyi iki kez kullanır.
// Incorrect block-code generator.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
// listCode is used twice.
const code = `${listCode}[${listCode}.length - 1]`;
return [code, Order.MEMBER];
}
İç bloğun kodu her çalıştırıldığında farklı değerler oluşturuyorsa veya kodun yan etkileri varsa bu durum sorunlara neden olur. Örneğin, iç bloğun kodu aslında bir işlev çağrısıysa bu kod, aralık dışında bir duruma neden olabilir:
randomList()[randomList().length - 1]
Bu sorunu önlemek için kodunuz, bir iç bloğun kodunu tam olarak bir kez yürütmelidir. Bunu yapmanın iki yolu vardır:
Geçici değişkenler: İç bloğun kodunu değerlendirmenin sonucunu geçici bir değişkende önbelleğe alın ve bunun yerine geçici değişkeni kullanın. Bu yöntemi yalnızca bloğunuz bir ifade bloğuysa kullanabilirsiniz.
Yardımcı işlevler: Yapmanız gereken işi yapan bir işlev oluşturun ve iç bloğun kodunu değerlendirmenin sonucunu bu işleve bağımsız değişken olarak iletin. Bu yöntemi hem değer hem de ifade blokları için kullanabilirsiniz.
Geçici değişkenler
Geçici değişken, bir iç bloğun kod dize değerini depolar. Böylece kod yalnızca bir kez değerlendirilir ve daha sonra değere birden çok kez referans verilebilir.
Değer blokları tek bir kod satırı döndürmesi gerektiğinden, geçici değişkenler değer bloklarında kullanılamaz. Bunun yerine bir yardımcı program işlevi kullanın.
import {javascriptGenerator, Order} from 'blockly/javascript';
// Correct block-code generator for a statement block that prints the last element of a list.
javascriptGenerator.forBlock['print_last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
// Get the name of a temporary variable.
const listVar = generator.nameDB_.getDistinctName(
'temp_list', Blockly.names.NameType.VARIABLE);
// Evaluate listCode once and assign the result to the temporary variable.
const code = `var ${listVar} = ${listCode};\n`;
// Print the last element of the list.
code += `print(${listVar}[${listVar}.length - 1]);\n`;
return code;
}
Örneğin, iç bloğun kodu randomList()
işlev çağrısıysa oluşturulan kod şudur:
var temp_list = randomList();
print(temp_list[temp_list.length - 1]);
getDistinctName
çağrısı, istediğiniz değişken adını alır ve kullanıcı tanımlı değişkenlerle çakışmayan bir ad döndürür.
Gereksiz kodu azaltın
Geçici değişkenlerin dezavantajı, iç bloğun kodu bir işlev veya ifade değilse gereksiz kod elde etmenizdir:
// Assigning to temp_list is unnecessary.
var temp_list = foo;
print(temp_list[temp_list.length - 1]);
Daha temiz kod oluşturmak için iç bloğun kodunun bir değer olup olmadığını kontrol edebilir ve geçici değişkeni yalnızca değer değilse dahil edebilirsiniz.
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`;
}
Yardımcı işlevler
Yardımcı program işlevi, oluşturulan kod dizesinin bir parçası olarak dahil edilen geliştirici tanımlı bir işlevdir. İç blok kodunun yalnızca bir kez değerlendirildiğinden ve ardından değere birden çok kez referans verilebileceğinden emin olmak için bunları kullanabilirsiniz.
Yardımcı işlevler, değer bloklarında ve ifade bloklarında kullanılabilir. Ancak ifade bloklarında genellikle daha okunaklı olan geçici değişkenler kullanılmalıdır.
import {javascriptGenerator, Order} from 'blockly/javascript';
// Correct block-code generator for a value block that gets the last element of a list.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.NONE);
// Create a function that accepts a list and returns its last element. The
// language generator adds this function to your code.
const functionName = generator.provideFunction_(
'list_lastElement',
[
`function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) {`,
` return list[list.length - 1];`,
`}`
]
);
// Create an expression that calls the function with listCode as its argument.
// This evaluates listCode once and passes the resulting list to the function.
const code = `${functionName}(${listCode})`;
return [code, Order.FUNCTION_CALL];
}
Örneğin, iç bloğun kodu randomList()
işlev çağrısıysa oluşturulan kod şudur:
// This code is added to the overall code returned by the code generator.
function list_lastElement(list) {
return list[list.length - 1];
}
// This code is returned by your inner block.
list_lastElement(randomList());
İşlevi sağlama
provideFunction_
kullanarak blok kod oluşturucuların içinde yardımcı işlevler tanımlayabilirsiniz. Bu işlev, yardımcı program işleviniz için istediğiniz adı ve işlevin tanımını içeren bir kod dizesi dizisi alır. Bu işlev, yardımcı işlevinizi kullanıcı tanımlı işlevlerle çakışmayacak şekilde değiştirdikten sonra işlevinizin adını döndürür.
provideFunction_
, yardımcı program işlevi tanımlarını da tekilleştirir. Böylece, her yardımcı program işlevi, onu tanımlayan blok türü birden fazla kez mevcut olsa bile yalnızca bir kez bulunur.
Öncelikleri güncelleme
Bir yardımcı program işlevi tanımlarken blok kodu oluşturucuya dahil edilen öncelik sıralarını (parantezlerin nasıl eklendiğini tanımlayan) da güncellemeniz gerekir.
Öncelik her zaman blok kodu oluşturucu tarafından döndürülen kod dizesine dayanır. Yardımcı program işlevlerindeki operatörleri dikkate almaz. Bu nedenle, önceki örnekte valueToCode
çağrısı Order.NONE
olarak, döndürülen tuple ise Order.FUNCTION_CALL
olarak değiştirildi.