Functions are the fundamental building block of any applications in JavaScript.
// Named function
function add(x, y) {
return x + y;
}
// Anonymous function
let myAdd = function(x, y) { return x + y; };
// caputure variables (via scope)
let z = 100;
function addToZ(x, y) {
return x + y + z;
}
Function Types
Writting the function type
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number { return x + y; };
Inferring the types
“contextual typing”, a form of type inference (按上下文归类, 类型推断的一种)
就是 ts 会自己推导类型不用你乱七八糟写一堆
// myAdd has the full function type
let myAdd = function(x: number, y: number): number { return x + y; };
// The parameters 'x' and 'y' have the type number
let myAdd: (baseValue: number, increment: number) => number =
function(x, y) { return x + y; };
Optional and Default Parameters
ts 会严格比较函数参数个数
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
可以用 ?
实现可选参数, 必须放在 required parameters 后面
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // works correctly now
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
默认参数, 不一定要放在 required parameters 后面
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith"
let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result4 = buildName("Bob", "Adams"); // ah, just right
// 在 required parameters 前面
function buildName(firstName = "Will", lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams"
let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams"
Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. This means optional parameters and trailing default parameters will share commonality in their types.
function buildName(firstName: string, lastName?: string) {
// ...
}
function buildName(firstName: string, lastName = "Smith") {
// ...
}
// 所以上面两个函数的类型是一样的
// 都是 (firstName: string, lastName?: string) => string
Rest Parameters
reuqired, optional, default parameters 都是按个来算的
批量的参数就可以用 rest parameters (也可以直接使用 arguments
)
Rest parameters are treated as a boundless number of optional parameters.
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
this
In JavaScript, this
is a variable that’s set when a function is called
Understanding JavaScript Function Invocation and “this”
this
and arrow functions
Arrow functions capture the this where the function is created rather than where it is invoked
箭头函数的 this 是定义时所在的对象, 不是使用时所在的对象
this
parameters
即便用箭头函数保证了 this 正确, 但是 ts 对下面的 this.suits[pickedSuit] 也还是不能正确推导类型
这是因为此时箭头函数的 this 取决于 createCardPicker 的 this, 然而 createCardPicker this 也还不知道哪里来呢
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
// NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
所以可以使用 this parameter, 把接口定义出来, 给 ts 一个提示:
interface Card {
suit: string;
card: number;
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;
}
let deck: Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
// NOTE: The function now explicitly specifies that its callee must be of type Deck
createCardPicker: function(this: Deck) {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
Overloads
The answer is to supply multiple function types for the same function as a list of overloads
就是写多个 fucntion types, 只写一个函数实现 (感觉这样的重载看起来有点奇怪…)
声明的 function types 组成一个 overload list
在 overload list 从上到下匹配, 匹配到第一个成功的就不理后面的了, 所以越精确的写在越前面
let 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") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);