Khối giá trị tương ứng với biểu thức. Khi sử dụng một khối giá trị làm khối bên trong, bạn có thể cần sử dụng biểu thức mà khối đó tạo ra nhiều lần trong mã của khối. Ví dụ: một khối lấy phần tử cuối cùng của danh sách sử dụng biểu thức tạo danh sách hai lần.
// 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];
}
Điều này gây ra sự cố nếu mã của khối bên trong tạo ra các giá trị khác nhau mỗi khi được thực thi hoặc nếu mã có hiệu ứng phụ. Ví dụ: nếu mã của khối bên trong thực sự là một lệnh gọi hàm, thì mã cụ thể này có thể gây ra tình trạng ngoài phạm vi:
randomList()[randomList().length - 1]
Để tránh vấn đề này, mã của bạn phải thực thi mã của một khối bên trong chính xác một lần. Có hai cách để thực hiện điều này:
Biến tạm thời: Lưu kết quả đánh giá mã của khối bên trong vào bộ nhớ đệm trong một biến tạm thời và sử dụng biến tạm thời đó. Bạn chỉ có thể sử dụng phương thức này nếu khối của bạn là khối câu lệnh.
Hàm tiện ích: Tạo một hàm thực hiện công việc bạn cần làm và truyền kết quả đánh giá mã của khối bên trong làm đối số cho hàm này. Bạn có thể sử dụng phương thức này cho cả giá trị và khối câu lệnh.
Biến tạm thời
Biến tạm thời lưu trữ giá trị của chuỗi mã của một khối bên trong để mã chỉ được đánh giá một lần, sau đó giá trị có thể được tham chiếu nhiều lần.
Bạn không thể sử dụng biến tạm thời trong các khối giá trị vì các khối giá trị phải trả về một dòng mã duy nhất. Thay vào đó, hãy sử dụng hàm tiện ích.
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;
}
Ví dụ: nếu mã của khối bên trong là lệnh gọi hàm randomList()
, thì mã được tạo sẽ là:
var temp_list = randomList();
print(temp_list[temp_list.length - 1]);
Lệnh gọi getDistinctName
sẽ lấy tên biến bạn muốn và trả về một tên không xung đột với bất kỳ biến nào do người dùng xác định.
Giảm mã thừa
Nhược điểm của biến tạm thời là nếu mã của khối bên trong là một giá trị và không phải là hàm hoặc biểu thức, thì bạn sẽ nhận được mã thừa:
// Assigning to temp_list is unnecessary.
var temp_list = foo;
print(temp_list[temp_list.length - 1]);
Để tạo mã gọn gàng hơn, bạn có thể kiểm tra xem mã của khối bên trong có phải là một giá trị hay không và chỉ đưa biến tạm thời vào nếu không phải.
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`;
}
Hàm hiệu dụng
Hàm tiện ích là một hàm do nhà phát triển xác định, được đưa vào chuỗi mã được tạo. Bạn có thể sử dụng các giá trị này để đảm bảo rằng mã khối bên trong chỉ được đánh giá một lần, sau đó giá trị có thể được tham chiếu nhiều lần.
Bạn có thể sử dụng các hàm tiện ích trong các khối giá trị và khối câu lệnh. Tuy nhiên, các khối câu lệnh thường nên sử dụng biến tạm thời, thường dễ đọc hơ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];
}
Ví dụ: nếu mã của khối bên trong là lệnh gọi hàm randomList()
, thì mã được tạo sẽ là:
// 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());
Cung cấp hàm
Bạn có thể xác định các hàm tiện ích bên trong trình tạo mã khối bằng cách sử dụng provideFunction_
. Hàm này nhận tên bạn muốn cho hàm tiện ích và một mảng các chuỗi mã chứa định nghĩa của hàm. Hàm này trả về tên kết quả của hàm tiện ích, sau khi (có thể) sửa đổi hàm đó để không xung đột với các hàm do người dùng xác định.
provideFunction_
cũng loại bỏ các định nghĩa hàm tiện ích trùng lặp, để mỗi hàm tiện ích chỉ tồn tại một lần, ngay cả khi loại khối xác định hàm đó tồn tại nhiều lần.
Cập nhật thứ tự ưu tiên
Khi xác định một hàm tiện ích, bạn cũng nên cập nhật thứ tự ưu tiên (xác định cách chèn dấu ngoặc đơn) có trong trình tạo mã khối.
Mức độ ưu tiên luôn dựa trên chuỗi mã do trình tạo mã khối trả về. Hàm này không quan tâm đến các toán tử bên trong hàm tiện ích. Vì vậy, trong ví dụ trước, lệnh gọi valueToCode
đã được thay đổi thành Order.NONE
và tuple trả về đã được thay đổi thành Order.FUNCTION_CALL
.