openplanning

Hướng dẫn và ví dụ TypeScript Closures

  1. Closure là gì?
  2. Cú pháp mũi tên
  3. Định nghĩa một kiểu hàm
  4. Kiểu hàm trong tham số

1. Closure là gì?

Trong ngôn ngữ lập trình TypeScript, Closure (bao đóng) là một hàm đặc biệt.
  • Giống như hàm, Closure là một khối lệnh với các tham số và có thể trả về một giá trị hoặc không trả về gì cả.
  • Khác với hàm, Closure không có tên, tuy nhiên bạn có thể định danh nó thông qua một biến.
Cú pháp:
// Closure syntax
function(arg1: data_type1, arg2: data_type2, argN: data_typeN) {
   // Statements
}
// Declare a variable as an alias for Closure
var alias = function(arg1: data_type1, arg2: data_type2, argN: data_typeN) {
   // Statements
};
Ví dụ dưới đây cho thấy sự khác biệt giữa một hàm và một closure. Kết luận: closure là một hàm không có tên.
// This is a function called sayHello
function sayHello(name: string) {
    console.log(`Hello ${name}`);
}
// This is a closure (A function without name)
function (name: string) {
    console.log(`Hello ${name}`);
}
Về cơ bản, nếu bạn tạo ra một Closure mà không sử dụng ngay lập tức bạn phải định danh cho nó, nếu không trình biên dịch sẽ thông báo lỗi. Chẳng hạn:
Closure ID Example
// Compile Error!!!!!
function(a: number, b: number) {
    return a + b;
}
// OK
var closureId = function(a: number, b: number) {
    return a + b;
}
Bạn có thể không cần định danh cho một Closure nếu bạn tạo ra nó và gọi nó một cách trực tiếp.
closure_ex1.ts
// Create a Closure and call it directly!
(function (name: string) {
    console.log(`Hello ${name}`);
})('Tom');

// --- Equivalent to: ---

// Identifier for a closure:
var sayHello = function (name: string) {
    console.log(`Hello ${name}`);
};
// Call closure via identifier:
sayHello('Tom');
Một ví dụ khác:
closure_ex2.ts
// Create a Closure and call it directly!
var result1 = (function (a: number, b: number) {
    return a + b;
})(100, 200);

// --- Equivalent to: ---

// Identifier for a closure:
var sum = function (a: number, b: number) {
    return a + b;
};
// Call closure via identifier:
var result2 = sum(100, 200);

2. Cú pháp mũi tên

TypeScript cho phép bạn khai báo một Closure thông qua cú pháp mũi tên (arrow), cú pháp này cũng thường được gọi là cú pháp Lambda. So với cú pháp truyền thống, cú pháp mũi tên bỏ đi từ khoá function và thêm một mũi tên ( => ) vào giữa khối tham số và khối nội dung.
// Arrow Syntax (Lambda Syntax):
(arg1: data_type1, arg2: data_type2, argN: data_typeN) => {
    // Statements
}

// Traditional Syntax:
function(arg1: data_type1, arg2: data_type2, argN: data_typeN)  {
    // Statements
}
Ví dụ:
closure_arrow_ex1.ts
// Create a Closure with Arrow Syntax.
var introduction = (name: string, country?: string) => {
    if (country) {
        console.log(`Hello, My name is ${name} from ${country}`);
    } else {
        console.log(`Hello, My name is ${name}`);
    }
};
// Call the Closure
introduction('Tom', 'USA');

// --- Equivalent to: ----

// Create a Closure with Arrow Syntax and call it directly:
((name: string, country?: string) => {
    if (country) {
        console.log(`Hello, My name is ${name} from ${country}`);
    } else {
        console.log(`Hello, My name is ${name}`);
    }
})('Tom', 'USA');
Nếu nội dung của Closure chỉ bao gồm duy nhất một biểu thức, bạn có thể viết nó một cách ngắn gọn hơn:
var closureId1 =  (arg1: data_type1, arg2: data_type2, argN: data_typeN)  => {
    console.log('Something');
}
// --- Equivalent to: ----
var closureId1 =  (data_type1 arg1, data_type2 arg2, data_typeN argN) => console.log('Something');

var closureId2 =  function(arg1: data_type1, arg2: data_type2, argN: data_typeN) => {
    return a_value;
}
// --- Equivalent to: ----
var closureId2 =  function(arg1: data_type1, arg2: data_type2, argN: data_typeN) => a_value;
Ví dụ:
closure_arrow_ex2.ts
// Create a Closure
var minus = (a: number, b: number) => a - b;

var result = minus(100, 200); // Call a closure.
console.log(`result = ${result}`);

// Create a Closure
var sayBye = (name: string) => console.log(`Bye ${name}`);
sayBye('Tom'); // Call a closure.
Output:
result = -100
Bye Tom

3. Định nghĩa một kiểu hàm

Trong TypeScript, từ khoá type được sử dụng để định nghĩa một kiểu dữ liệu mới. Trong phần này chúng ta sẽ thảo luận về cách sử dụng từ khoá type để định nghĩa một kiểu hàm (Cũng được gọi là kiểu Closure).
Cú pháp:
type Function_Type_Name = (arg1: data_type1, arg2: data_type2, argN: data_typeN) => return_type;
Ví dụ: Định nghĩa một kiểu hàm (Function Type) chấp nhận một tham số kiểu number và trả về một giá trị kiểu number:
function_type_ex1.ts
// A Function Type:
type TaxCalculator = (amount: number) => number;
 
function function_type_ex1_test()  {
    var usTaxCalculator: TaxCalculator = (amount: number) =>  {
        return amount * 10 / 100;
    };
    var vnTaxCalculator: TaxCalculator = (amount: number) =>  amount * 5 / 100;

    var caTaxCalculator: TaxCalculator = function(amount: number)  {
        return amount * 8 / 100;
    }
    const AMOUNT = 1000;
    var usTaxAmount = usTaxCalculator(AMOUNT);
    var vnTaxAmount = vnTaxCalculator(AMOUNT);
    var caTaxAmount = caTaxCalculator(AMOUNT);

    console.log(`Tax amount according to US calculation: ${usTaxAmount}`);
    console.log(`Tax amount according to Vietnam calculation: ${vnTaxAmount}`);
    console.log(`Tax amount according to Canada calculation: ${caTaxAmount}`);
}
function_type_ex1_test(); // Call the function.
Output:
Tax amount according to US calculation: 100
Tax amount according to Vietnam calculation: 50
Tax amount according to Canada calculation: 80

4. Kiểu hàm trong tham số

Kiểu hàm (Function Type) có thể xuất hiện như là một tham số của một hàm, closure, phương thức hoặc constructor khác.
function_type_in_args_ex1.ts
// Define a Function Type:
type MyTaxCalculator = (value: number) => number;

function calculateTaxAmount1(amount: number, calculator: MyTaxCalculator) {
    var taxAmount = calculator(amount);
    console.log(`Tax Amount: ${taxAmount}`);
}
// --- Equivalent to: ---

function calculateTaxAmount2(amount: number, calculator: (value: number) => number) {
    var taxAmount = calculator(amount);
    console.log(`Tax Amount: ${taxAmount}`);
}
Ví dụ:
function_type_in_args_ex2.ts
// A Function accepts 2 parameters:
// 1 - amount: number
// 2 - calculator : (number) => (number)
function printTaxAmount(amount: number, calculator: (value: number) => number) {
    var taxAmount = calculator(amount);
    console.log(`Tax Amount: ${taxAmount}`);
}
function function_type_in_args_ex2_test() {
    // Function Type: (number) => (number)
    var usTaxCalculator = (value: number) => {
        return value * 10 / 100;
    };
    // Function Type: (number) => (number)
    var vnTaxCalculator: TaxCalculator = (value: number) => value * 5 / 100;

    printTaxAmount(1000, usTaxCalculator);
    printTaxAmount(1000, vnTaxCalculator);
    printTaxAmount(1000, (value: number) => value * 8 / 100);
}
function_type_in_args_ex2_test(); // Call the function.
Output:
Tax Amount: 100
Tax Amount: 50
Tax Amount: 80