Функции
Функции - фундаментальные строительные блоки приложений на JavaScript. С помощью функций строятся уровни абстракции, организуются классы, видимость информации и модули приложения. В TypeScript, имеющем классы и модули, функции все равно играют ключевую роль. TypeScript также добавлет несколько новых возможностей к функциям JavaScript для того, чтобы упростить работу.Функции
Так же как и в JavaScript, в TypeScript функции могут быть как именованными так и анонимными://Именованная функция function add(x, y) { return x+y; } //Анонимная функция var myAdd = function(x, y) { return x+y; };
Типы возвращаемых значений
Можно добавить тип для каждого параметра и возвращаемого значения функций. TypeScript может определить тип возвращаемого значения по выражению return, поэтому тип возвращаемого значения можно не указывать.
function add(x: number, y: number): number { return x+y; } var myAdd = function(x: number, y: number): number { return x+y; };
Написание типа функции
Функция представляет из себя тип. Рассмотрим полное написание типа функции.var myAdd: (x:number, y:number)=>number = function(x: number, y: number): number { return x+y; };
Тип функции имеет две одинаковые части: тип агрументов и тип возвращаемого значения. Когда функция пишется через полное описание типа функции, указывать эти две части обязательно. Параметры типа функции описываются как список параметров, где для каждого параметра указывается имя и тип. При этом имя указывается только для улучшения читабельности. Поэтому имена можно указать любые:
var myAdd: (baseValue:number, increment:number)=>number = function(x: number, y: number): number { return x+y; };
Вторая часть - это возвращаемое значение. Тип возвращаемого значения указывается после стрелки =>. В описании типа функции указывать тип возвращаемого значения обязательно, поэтому, ксли функция не возвращает значение, необходимо указать 'void', но не оставлять тип возвращаемого значения пустым.
Важно иметь в виду, что только параметры и тип возвращаемого значения формируют тип функции.
Выведение типов
Компилятор TypeScript может сам определять тип выражения, основываясь на типах аргументов:// myAdd имеет полное описание типа функции var myAdd = function(x: number, y: number): number { return x+y; }; // Параметры 'x' и 'y' имеют тип number var myAdd: (baseValue:number, increment:number)=>number = function(x, y) { return x+y; };
Это называется 'контекстная типизация'. Это позволяет сократить усилия, чтобы программа была типизированной.
Необязательные параметры и параметры по умолчанию
В отличие от JavaScript, в TypeScript каждый параметр функции обязательный. Это не означает, что он не может быть 'null', при вызове функции компилятор проверяет, что указаны все параметры. Количество передаваемых в функцию параметров должно совпадать с количеством параметров, описанных в функции.function buildName(firstName: string, lastName: string) { return firstName + " " + lastName; } var result1 = buildName("Bob"); //ошибка, мало параметров var result2 = buildName("Bob", "Adams", "Sr."); //ошибка, много параметров var result3 = buildName("Bob", "Adams"); //нет ошибки
В JavaScript каждый параметр считается необязательным, и пользователи могут не указывать их. Тогда значения этих параметров будут неопределенными ('undefined'). Такой же функциональности в TypeScript можно добиться использованием '?' рядом с параметрами, которые мы хотим сделать необязательнвми. Например, если мы хотим, чтобы последний параметр был необязательным:
function buildName(firstName: string, lastName?: string) { if (lastName) return firstName + " " + lastName; else return firstName; } var result1 = buildName("Bob"); //работает var result2 = buildName("Bob", "Adams", "Sr."); //ошибка, много параметров var result3 = buildName("Bob", "Adams"); //работает
Необязательные параметры должны строго следовать после обязательных.
В TypeScript можно указать значение необязательного параметра по умолчанию, если пользователь не его указал. Например, установим значение по умолчанию для последнего параметра "Smith".
function buildName(firstName: string, lastName = "Smith") { return firstName + " " + lastName; } var result1 = buildName("Bob"); //работает var result2 = buildName("Bob", "Adams", "Sr."); //ошибка, много параметров var result3 = buildName("Bob", "Adams"); //работает
Параметры со значением по умолчанию, так же как и необязательные параметры, должны строго следовать после обязательных параметров.
Необязательные параметры и параметры со значением по умолчанию тоже показывают какого они типа. Оба варианта:
function buildName(firstName: string, lastName?: string) {
и
function buildName(firstName: string, lastName = "Smith") {
одного и того же типа "(firstName: string, lastName?: string)=>string". Значение по умолчанию для необязательного параметра не указывается, а указывается только то, что параметр необязательный.
Однотипные параметры
Обязательные, необязательные и параметры со значением по умолчанию имеют кое-что общее: они представляют из себя параметр с одним значением. Иногда, необходимо работать с множеством параметров как с группой, или, возможно, заранее не известно сколько параметров функция в конечном счете принимает. В JavaScript можно работать с аргументами функции, которые представляют из себя переменные находящиеся вне тела функции.В TypeScript аргументы можно объединить в переменную:
function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } var employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
Однотипные параметры рассматриваются как неограниченное число необязательных параметров. Можно не указывать ни одного или указать сколько угодно. Компилятор сформирует массив аргументов, которые указаны после многоточния (...), и этот массив будет доступен в тебе функции.
Многоточние также используется в типе функции с однотипными параметрами:
function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } var buildNameFun: (fname: string, ...rest: string[])=>string = buildName;
Ламбда и ключевое слово this
Как работает 'this' в функциях JavaScript это очень непростая тема для программистов использующих JavaScript. В действительности, понимание как работает this часто приходит только с опытом использования JavaScript. Так как TypeScript это расширение JavaScript, то разработчику TypeScript также необходимо изучить как использовать 'this' и как определить когда оно используется неправильно. Целая статья может быть написана на тему как работает 'this' В JavaScript. Рассмотрим только основы.В JavaScript 'this' это переменная, которая устанавливается, когда вызывается функция. Это очень полезная возможность, но она устанавливается с учетом понимания того, в каком контексте выполняется функция. Это может ввести в заблуждение, например, когда используется функция обратного вызова
Например:
var deck = { suits: ["hearts", "spades", "clubs", "diamonds"], cards: Array(52), createCardPicker: function() { return function() { var pickedCard = Math.floor(Math.random() * 52); var pickedSuit = Math.floor(pickedCard / 13); return {suit: this.suits[pickedSuit], card: pickedCard % 13}; } } } var cardPicker = deck.createCardPicker(); var pickedCard = cardPicker(); alert("card: " + pickedCard.card + " of " + pickedCard.suit);
Здесь вместо сообщения будет показана ошибка. Потому что используется 'this' созданный в функции 'createCardPicker', который окажется установленный в 'window', а не на объект 'deck'. Это получается в результате вызова функции 'cardPicker()'. Здесь не используется динамическое связывание для 'this' как это делается для Window. (надо иметь в виду: в строгом режиме, this будет 'undefined', а не window).
Это можно исправить, если убедиться, что функция связана с правильным 'this', прежде чем вернуться в функцию, которая будет использоваться позже. В этом случае, независимо от того как она будет использоваться позже, все равно будет возможноть видеть оригинальный объект 'deck'.
Чтобы это исправить, перепишем функцию так, чтобы использовалась лямда ( ()=>{} ). Тогда 'this' будет автоматически установлен, когда функция создана, а не когда она вызывается:
var deck = { suits: ["hearts", "spades", "clubs", "diamonds"], cards: Array(52), createCardPicker: function() { // Notice: the line below is now a lambda, allowing us to capture 'this' earlier return () => { var pickedCard = Math.floor(Math.random() * 52); var pickedSuit = Math.floor(pickedCard / 13); return {suit: this.suits[pickedSuit], card: pickedCard % 13}; } } } var cardPicker = deck.createCardPicker(); var pickedCard = cardPicker(); alert("card: " + pickedCard.card + " of " + pickedCard.suit);
Для большего понимания работы 'this' почитайте Yahuda Katz's Understanding JavaScript Function Invocation and “this”.
Перегрузка
JavaScriptпо своей сути очень динамический язык. И это не редкость, когда функция возвращает разные типы объектов, в зависимости от того, какие параметры в нее были переданы.var suits = ["hearts", "spades", "clubs", "diamonds"]; function pickCard(x): any { // Check to see if we're working with an object/array // if so, they gave us the deck and we'll pick the card if (typeof x == "object") { var pickedCard = Math.floor(Math.random() * x.length); return pickedCard; } // Otherwise just let them pick the card else if (typeof x == "number") { var pickedSuit = Math.floor(x / 13); return { suit: suits[pickedSuit], card: x % 13 }; } } var myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }]; var pickedCard1 = myDeck[pickCard(myDeck)]; alert("card: " + pickedCard1.card + " of " + pickedCard1.suit); var pickedCard2 = pickCard(15); alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
Здесь функция 'pickCard' возвращает разные вещи в зависимости от того, что в нее передано.Если в нее передан deck, она вернет card. Если в нее передан card, то указывается какой именно card передан. Но как это описывается в системе типов?
Ответ - использовать перегрузку. В зависимости от параметров компилятор выбирает какую вызывать функцию. Например:
var suits = ["hearts", "spades", "clubs", "diamonds"]; function pickCard(x: {suit: string; card: number; }[]): number; function pickCard(x: number): {suit: string; card: number; }; function pickCard(x): any { // Check to see if we're working with an object/array // if so, they gave us the deck and we'll pick the card if (typeof x == "object") { var pickedCard = Math.floor(Math.random() * x.length); return pickedCard; } // Otherwise just let them pick the card else if (typeof x == "number") { var pickedSuit = Math.floor(x / 13); return { suit: suits[pickedSuit], card: x % 13 }; } } var myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }]; var pickedCard1 = myDeck[pickCard(myDeck)]; alert("card: " + pickedCard1.card + " of " + pickedCard1.suit); var pickedCard2 = pickCard(15); alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
При этом компилятор для определения подходящей функции будет пробовать их попорядку. И как только найдет функцию с подходящими параметрами, будет считать, что вызывается именно она. Это надо учитывать при описании порядка функций.
Комментариев нет :
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.