技术分享

使用TypeScript开发微信小程序(3)——基础:函数(Function)


函数是 JavaScript 应用程序的基础, 它可以实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方,TypeScript 为JavaScript 函数添加了额外的功能,更容易地使用。 

函数

和JavaScript一样,TypeScript函数可以创建有名字的函数和匿名函数。 可以随意选择适合应用程序的方式,不论是定义一系列API函数还是只使用一次的函数。

    function add1(x: number, y: number): number {        return x + y;
    }    let add2 = function (x: number, y: number): number { return x + y; };

完整函数类型

    let sub1: (x:number, y:number) => number =        function(a: number, b: number): number { return x-y; };

函数类型包含两部分:参数类型和返回值类型。 当写出完整函数类型的时候,这两部分都是需要的。 只要参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确。对于返回值, 在函数和返回值类型之前使用( =>)符号,使之清晰明了。返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为 void 而不能留空。

推断类型

    let sub2 = function(a: number, b: number): number { return a - b; };

如果在赋值语句的一边指定了类型但是另一边没有类型的话,TypeScript编译器会自动识别出类型。

可选参数

TypeScript里的每个函数参数都是必须的。 这不是指不能传递 null或undefined作为参数,而是说编译器检查用户是否为每个参数都传入了值。 编译器还会假设只有这些参数会被传递进函数。 简短地说,传递给一个函数的参数个数必须与函数期望的参数个数一致。

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

    function buildName1(firstName: string, lastName?: string) {        if (lastName)            return firstName + " " + lastName;        else            return firstName;
    }    console.log(buildName1("Bob")); // 输出:Bob    // console.log(buildName1("Bob", "Adams", "Sr.")); // Error    console.log(buildName1("Bob", "Adams")); // 输出:Bob Adams

可选参数必须跟在必须参数后面。

默认参数

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

    function buildName2(firstName: string, lastName = "Smith") {
        return firstName + " " + lastName;
    }
    console.log(buildName2("Bob")); // 输出:Bob Smith
    console.log(buildName2("Bob", undefined)); // 输出:Bob Smith
    // console.log(buildName2("Bob", "Adams", "Sr.")); // Error
    console.log(buildName2("Bob", "Adams")); // 输出:Bob Adams

在所有必须参数后面的带默认初始化的参数都是可选的,与可选参数一样,在调用函数的时候可以省略。 也就是说可选参数与末尾的默认参数共享参数类型。

与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值。

剩余参数

必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 如果同时操作多个参数,或者并不知道会有多少参数传递进来。 在JavaScript里,可以使用 arguments 来访问所有传入的参数。

在 TypeScript 里,可以把所有参数收集到一个变量里:

    function buildName3(firstName: string, ...restOfName: string[]) {        return firstName + " " + restOfName.join(" ");
    }    console.log(buildName3("Joseph", "Samuel", "Lucas", "MacKinzie")); // 输出:Joseph Joseph Lucas Lucas

剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是在省略号( …)后面给定的名字,可以在函数体内使用这个数组。这个省略号( …)也会在带有剩余参数的函数类型定义上使用到。


箭头函数

箭头函数(lambda表达式)是 ES6 在语法上提供的一个很好的特性。

    var array = [1, 2, 3];
    array.forEach(v => console.log(v)); // 输出: 1 2 3

普通 function 函数和箭头函数的行为有区别,箭头函数没有它自己的 this 值,箭头函数内的 this 值继承自外围作用域。

    var array = [1, 2, 3];
    array.forEach(v => console.log(v)); // 输出: 1 2 3    class Handler {
        message: string;
        change = (m: string) => { this.message = m };
        output = () => { console.log(this.message) };
    }    let handler = new Handler();
    handler.change("Hello");
    handler.output();

重载

JavaScript 本身是个动态语言,JavaScript 里函数根据传入不同的参数而返回不同类型的数据是很常见的。可以为同一个函数提供多个函数类型定义来进行函数重载, 编译器会根据这个列表去处理函数的调用。

    class FooClass {
        public bar(s: string): number;
        public bar(n: number): string;
        public bar(arg: string | number): any {            if (typeof arg === 'number')                return arg.toString();            if (typeof arg === 'string')                return arg.length;
        }
    }

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

参考资料

  • TypeScript官网
  • TypeScript中文网

其他

  • 完整代码:https://github.com/guyoung/GyWxappCases/tree/master/TypeScript