betacode

Замыкания (Closure) в TypeScript

  1. Что такое Closure?
  2. Синтаксис стрелки
  3. Определение типа функции
  4. Тип функции в параметре

1. Что такое Closure?

В языке программирования TypeScript, Closure (закрытая сумка) - это специальная функция.
  • Подобно функции, Closure представляет собой блок операторов с параметрами и может возвращать значение или ничего.
  • В отличие от функции, Closure не имеет имени. Однако вы можете идентифицировать его с помощью переменной.
Синтаксис:
// 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
};
В приведенном ниже примере показана разница между функцией и closure. Вывод: closure - это функция без имени.
// 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}`);
}
В принципе, если вы создаете Closure, которое не используете немедленно, вы должны его идентифицировать, иначе компилятор сообщит об ошибке. Например:
Closure ID Example
// Compile Error!!!!!
function(a: number, b: number) {
    return a + b;
}
// OK
var closureId = function(a: number, b: number) {
    return a + b;
}
Возможно, вам не понадобится идентификатор для Closure, если вы создадите его и вызовете напрямую.
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');
Другой пример:
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. Синтаксис стрелки

TypeScript позволяет объявлять Closure с использованием синтаксиса стрелок (arrow), который также широко известен как Lambda-синтаксис. По сравнению с традиционным синтаксисом, синтаксис стрелки опускает ключевое слово function и добавляет стрелку (=>) между блоком параметров и блоком содержимого.
// 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
}
Например:
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');
Если содержимое Closure состоит только из одного выражения, вы можете написать его более лаконично:
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;
Например:
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. Определение типа функции

В TypeScript, ключевое слово type используется для определения нового типа данных. В этом разделе мы обсудим, как использовать ключевое слово type для определения типа функции (также называемого типом Closure).
Синтаксис:
type Function_Type_Name = (arg1: data_type1, arg2: data_type2, argN: data_typeN) => return_type;
Например: Определите тип функции, которая принимает параметр типа number и возвращает значение типа 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. Тип функции в параметре

Тип функции (Function Type) может отображаться как параметр другой функции, closure, метода или constructor.
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}`);
}
Например:
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