DAY 3
0
Modern Web

# Functions

`Function` 在 Javascript 中是很基本的型態，可以用在隱藏資訊，或攥寫模組等功用

Javascript 中基本的 `Function` 有兩種

``````function add(x, y){
return x+y;
}

let myAdd = function(x, y){return x+y;}
``````

``````let z = 100;
return x + y + z;
}
``````

``````function add (x: number, y: number): number{
return x + y;
}

let myAdd = function(x: number, y: number): number{return x+y;};
``````

``````let myAdd: (x: number, y: number) => number = function(x: number, y: number): number{
return x+y;
}
``````

``````let myAdd = function(x: number, y: number): number{
return x + y;
};

let myAdd2: (x: number, y: number) => number = function(x, y){return x + y;};
``````

### Optional and Default Parameters

`TypeScript` 中指定每個參數不能是 `null` 或是 `undefined`

``````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
``````

``````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
``````

`TypeScript` 非必要參數必須要在 必要參數的後面， `TypeScript` 也可以提供預設值的設定

``````function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}

let res1 = buildName("Bob");                  // works correctly now, returns "Bob Smith"
let res2 = buildName("Bob", undefined);       // still works, also returns "Bob Smith"
// let res3 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let res4 = buildName("Bob", "Adams");         // ah, just right
``````

### Rest Parameters

`ES6` 也有一種特性 Rest

``````function buildName4(firstName: string, ...restOfName: string[]) {
console.log(`firstName: \${firstName}`);
console.log(`restOfName: \${restOfName}`);
return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName4("Joseph", "Samuel", "Lucas", "MacKinzie");
``````

### this

``````let deck = {
cards: Array(52),
createCardPicker: function() {
return function() {
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);
``````

``````let deck = {
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 parameters

``````function f(this: void){
// ....
}
``````

``````interface Card{
suit: string;
card: number
}
interface Deck{
suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;
}

let deck: Deck = {
cards: Array(52),
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};
}
}
}
``````

`interface` 中的 `createCardPicker` 有宣告了 this 的型態

`Deck` 而不是 `any` 所以 `--noImplicitThis` 不會有錯誤

#### this parameters in callbacks

``````interface UIElement{
addClickListener(onClick: (this: void, e: Event => void): void)
}
``````

`this: void` 代表 `addClickListener` 預計 `onClick` 是一個 `Fucntion` 並沒有 `this` 的類別

``````class Handler {
info: string;
// oops, used this here. using this callback would crash at runtime
this.info = e.message;
}
}
let h = new Handler();
``````

Javascript 是一個動態繼承的程式語言，一個函式藉由輸入值得到不同的回傳值是十分常見的

``````let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
} 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 pickedCard01 = myDeck[pickCard(myDeck)];
console.log("card: " + pickedCard01.card + " of " + pickedCard01.suit);
console.log(`pickedCard01: \${JSON.stringify(pickedCard01)}`);
let pickedCard02 = pickCard(15);
console.log("card: " + pickedCard02.card + " of " + pickedCard02.suit);
console.log(`pickedCard02: \${JSON.stringify(pickedCard02)}`);
``````

`pickCard` 會依據我們傳進去的參數不同，回傳不同的資訊這樣的話我們該如何去定義呢？

``````let suits02 = ["hearts", "spades", "clubs", "diamonds"];

function pickCard1(x: { suit: string; card: number }[]): number;
function pickCard1(x: number): { suit: string; card: number };
function pickCard1(x): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
} else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits02[pickedSuit], card: x % 13 };
}
}

let myDeck02 = [
{ suit: "diamonds", card: 2 },
{ suit: "spades", card: 10 },
{ suit: "hearts", card: 4 }
];
let pickedCard001 = myDeck02[pickCard1(myDeck02)];
console.log("card: " + pickedCard001.card + " of " + pickedCard001.suit);

let pickedCard002 = pickCard1(15);
console.log("card: " + pickedCard002.card + " of " + pickedCard002.suit);
``````