hackftz

bits change world

导航

深入理解TypeScript——文档篇之函数

Posted on 2020-10-13 00:06  hackftz  阅读(38)  评论(0编辑  收藏  举报

一、函数类型

  1. 定义函数类型

    // 函数式声明
    function add(x: number, y: number): number {
        return x + y;
    }
    
    // 由变量指向的匿名函数
    let myAdd = function(x: number, y: number): number { return x + y; };
    
  2. 完整函数类型

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

    通常需要将类型抽离成接口,形成规范。

  3. 推断类型

    函数定义赋值语句一边有类型。

    // 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; };
    

二、可选参数、默认参数

​ ts中传递给一个函数的参数个数必须与函数期望的参数个数一致。

  1. 可选参数

    在TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能。

    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
    

    注意:可选参数必须跟在必须参数后面。

  2. 默认参数

    在TypeScript里,我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是undefined时。 它们叫做有默认初始化值的参数。

    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
    

    在所有必须参数后面的带默认初始化的参数都是可选的,与可选参数一样,在调用函数的时候可以省略。

    function buildName(firstName: string, lastName?: string) {
        // ...
    }
    
    function buildName(firstName: string, lastName = "Smith") { // lastName为可选,调用时可省略
        // ...
    }
    

    与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值。 例如,我们重写最后一个例子,让 firstName是带默认值的参数:

    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" 首个参数后有其他参数,则要取得默认值必须要传入undefined
    
  3. 剩余参数

    剩余参数会被当做个数不限的可选参数。

    function buildName(firstName: string, ...restOfName: string[]) {
      return firstName + " " + restOfName.join(" ");
    }
    
    let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
    
  4. this

    JavaScript里,this的值在函数被调用的时候才会指定。

    let deck = {
        suits: ["hearts", "spades", "clubs", "diamonds"],
        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); // error 找不到this
    

    箭头函数能保存函数创建时的 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);
    
  5. 重载

    方法是为同一个函数提供多个函数类型定义来进行函数重载。

    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);
    

    为了让编译器能够选择正确的检查类型,它与JavaScript里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。(大几率事件)