تتوافق مجموعات القيم مع التعبيرات. عند استخدام كتلة قيمة كتلة داخلية، قد تحتاج إلى استخدام التعبير الذي تنشئه أكثر من مرة في رمز كتلة. على سبيل المثال، تستخدم الكتلة التي تحصل على العنصر الأخير من قائمة تعبير الذي ينشئ القائمة مرتين.
// 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];
}
ويؤدي ذلك إلى حدوث مشاكل إذا كان رمز الكتلة الداخلية يُنشئ قيمًا مختلفة في كل مرّة يتم فيها تنفيذه، أو إذا كان للرمز تأثيرات جانبية. على سبيل المثال، إذا كان رمز المحاولة الداخلية عبارة عن طلب دالة، يمكن أن يؤدي هذا الرمز البرمجي تحديدًا إلى حالة خارج النطاق:
randomList()[randomList().length - 1]
لتجنّب هذه المشكلة، يجب أن ينفذ الرمز البرمجي رمزًا للوحدة الداخلية مرة واحدة فقط. وهناك طريقتان لذلك:
المتغيّرات المؤقتة: يمكنك تخزين نتيجة تقييم رمز القسم الداخلي مؤقتًا في متغيّر مؤقت واستخدام المتغيّر المؤقت بدلاً من ذلك. لا يمكنك استخدام هذه الطريقة إلا إذا كان العنصر عبارة عن ملف برمجي.
وظائف المرافق: أنشئ دالة تُنفِّذ العمل الذي تحتاج إلى تنفيذه وتُرسِل نتيجة تقييم رمز الكتلة الداخلية كوسيطة إلى هذه الدالة. يمكنك استخدام هذه الطريقة لكل من القيمة و كتل العبارة.
المتغيّرات المؤقتة
يخزِّن المتغيّر المؤقت قيمة سلسلة رمز الرمز البرمجي للوحدة الداخلية لكي يتم تقييم الرمز مرة واحدة فقط، ثم يمكن الإشارة إلى القيمة عدة مرات.
لا يمكن استخدام المتغيّرات المؤقتة في مجموعات القيم لأنّه يجب أن تُعيد مجموعات القيم سطرًا واحدًا من الرمز. استخدِم دالة مساعدة بدلاً من ذلك.
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;
}
على سبيل المثال، إذا كان رمز الكتلة الداخلية هو طلب الدالة randomList()
، يكون
الرمز الذي تم إنشاؤه على النحو التالي:
var temp_list = randomList();
print(temp_list[temp_list.length - 1]);
يأخذ طلب 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`;
}
الدوالّ الخدمية
دالة الأداة هي دالة يحدّدها المطوّر وتُدرَج كجزء من سلسلة الرمز المُنشَئ. يمكنك استخدامها للتأكّد من أنّ تقييم رمز الكتلة الداخلية يتم مرة واحدة فقط، وبعد ذلك يمكن الإشارة إلى القيمة عدة مرات.
يمكن استخدام دوالّ المرافق في كتل القيم وكتل العبارات. ومع ذلك، يجب أن تستخدِم كتل العبارة بشكل عام متغيّرات مؤقتة، والتي تكون عادةً أكثر سهولة في القراءة.
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];
}
على سبيل المثال، إذا كان رمز الكتلة الداخلية هو طلب الدالة randomList()
، يكون
الرمز الذي تم إنشاؤه على النحو التالي:
// 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());
تقديم الدالة
يمكنك تحديد دوال مساعدة داخل أدوات إنشاء الرموز البرمجية للوحدات باستخدام
provideFunction_
. يأخذ هذا الإجراء الاسم الذي تريده لدالة الأداة، و
صفيفًا من سلاسل الرموز البرمجية التي تحتوي على تعريف الدالة. ويعرض القيمة
الناتجة عن دالة الأداة، بعد تعديلها (ربما) كي لا تتعاضم
مع الدوالّ التي يحدّدها المستخدم.
تزيل provideFunction_
أيضًا تكرار تعريفات دوال الأدوات، بحيث لا تظهر كل دالة
أداة إلا مرة واحدة، حتى إذا كان نوع الكتلة الذي يحدّدها يظهر
مرارًا وتكرارًا.
تعديل الأولويات
عند تعريف دالة مساعدة، يجب أيضًا تعديل الأولويات (التي تحدّد كيفية إدراج الأقواس) المضمّنة في أداة إنشاء الرموز البرمجية للوحدات.
تستند الأولوية دائمًا إلى سلسلة الرمز التي يعرضها ملف بدء توليد رمز الوحدات. ولا يهتم بعوامل التشغيل داخل دوال المرافق. وبالتالي، في المثال السابق، تم تغيير طلب valueToCode
إلى Order.NONE
وتم تغيير مجموعة العناصر المعروضة عند الرجوع إلى Order.FUNCTION_CALL
.