函数

 TJS2 的函数和 子程序 大致上相同。即使没有返回值也会被作为函数来处理。
 作为类或对象的成员的函数又被称为“方法”。

函数的书写方式

 函数可以依照下面这样的格式来书写。

    function 函数名 ( 参数列表 )
    {
        函数的内容
    }


 首先,定义函数需要写下 function 关键字。然后在关键字后面写函数名。以后这个函数就用这个函数名来调用。
 函数的内容里可以写上想要在函数中执行的语句和代码段。


例:
    function test(a) { System.inform(a); }
    function func(a, b, c, d)
    {
        test(a);
        test(b);
        test(c);
        test(d);
        return a+b-c*d;
    }


对函数使用 instanceof 运算符和 "Function" 操作数的话,会返回真(按照上面的例子来说,func instanceof "Function" 为真)。

函数的调用

 函数使用 ( ) 运算符来调用,就象下面这样写。
    函数名( 参数 )
    没有参数的时候就写成 函数名( ) 。将复数的表达式指定为参数的时候应该用逗号分隔。

例:
    func();
    func(1+2, 1-2);
    func(func2());


    还有,没有指定表达式而空着的参数,会被看作指定了 void 。

例:
    func(,1); // 会被当作指定了 void, 1 
    func(,); // 会被当作指定了 void, void 

参数列表

 参数列表是那些用来接受传入的参数的变量的名字。函数被调用时传入的参数会按照参数列表中的顺序传递给各个变量。

例:
    function test(a, b, c)
    {
        // 这个时候就能使用 a 和 b 和 c 这3个变量了,
        // 传入的3个参数被代入到这3个变量中了。
        // 像 test(1, 2, 3) 这样调用的话, a 中会被代入 1 ,
        // b 中会被代入 2, c 中会被代入 3 。
    }


 这些参数都全局变量,在函数执行结束后这些参数就不能用了。

 在 TJS2 中,调用函数时提供的参数比函数定义的参数少或者多的话,是不会产生错误的。 ( 如果那个函数不是由TJS2写成的 ( 那函数的实体是由 C++ 等语言写成的 ) 就会产生错误,这是个例外 )。提供的参数比声明时多的话,多出的部分会被忽略,如果少的话,接收不到参数的变量会被传入 void 。

例:
    function test(a, b)
    {
        // 如果像 test(1) 这样调用,a 中会被代入 1 ,b 中会被代入 void 。
        // 如果像 test(1,2,3) 这样调用, a 中会被代入 1, b 中会被代入 2 ,3 会被忽略
    }


 参数列表中的各个参数可以在后面用 = 连接来指定默认值 ( 默认值参数 ) 。当某个参数被指定为 void 或者提供的参数比声明时的参数少时,会自动将默认值指定给对应的参数。

例:
    function test(a = -1, b = 1)
    {
        // 如果……
        // 像 test() 这样调用的话, a=-1, b=1
        // 像 test(5) 这样调用的话, a=5, b=1
        // 像 test(void,void) 这样调用的话, a=-1, b=1
        // 像 test(,4) 这样调用的话, a=-1, b=4
    }


 不需要接受参数的函数可以省略(不写)参数列表。

例:
    function test
    {
        // 不接受参数的函数
    }

表达式声明函数

 在表达式中使用 function 可以定义没有名字的函数,也就是 表达式声明函数 ( 匿名函数 ) 。
 在这种情况下会省略函数的名字。

例:
    var func = function(i) { return i*5; };
    var func2 = function { System.inform("hoge"); };
    var v = func(); // 调用 func 函数
    func2(); // 调用 func2 函数

参数的省略

 调用函数的时候将 ... 作为参数,就可以把函数调用表达式所在的函数所接受的参数照原样传入到被调用的函数中。即使参数的值被改变了,或者或者接受的参数数量不足,也会以那些参数传入时的内容和数量传给被调用的函数。

例:
    function test2(a, b)
    {
        // 函数的内容
    }
    
    function test()
    {
        test2(...);
        // 将传给 test 的参数,以参数传入时的内容和数量传给 test2
    }
    
    test(1, 2);
    // 因为 test 函数没有参数列表,1 和 2 这两个参数在传入 test 函数后会被忽略,
    // 但是,在 test 中被调用的 test2 函数仍然会接收到这两个参数。
    
    function test1(a, b = 2)
    {
        test2(...);
        // 将传给 test1 的参数,以参数传入时的内容和数量传给 test2
    }
    
    test1(1);
    // 在参数 1 被传入 test1 之后,因为参数数量不足,默认值 2 会被代入到 b 中,
    // 但是,在 test1 中被调用的 test2 函数只会接收到1个参数,就是 1 ,
    // 而不会接收到那个默认值 2 ,因为那不是调用函数时传入的参数。

 译者注:为了更好的说明问题,对上面的事例作了一些修改。

参数向数组的转换

 可以把参数转化为数组传入函数中。声明函数时将 '*' 加到参数名后面,就可以将传入的参数转化为数组。

例:
    function func(args*)
    {
        // args 就是将传入这个函数的参数作为元素的数组
        // 也就是说,像 func(1, 2, 3, 4) 这样调用的话,
        // 会按照 1 2 3 4 的顺序将4个参数作为元素装入 args 中。
    }


 也可以从参数列表的中间开始将后面的所有参数转化为数组传入。如果参数的数量不足,传入的数组可能是空的。

例:
    function func(x, args*)
    {
        // 也就是说,像 func(1, 2, 3, 4) 这样调用的话,
        // x 中会被代入 1 。然后, 2 3 4 这三个值会依次装入 args 。
        // 像 func(1) 这样调用的话,因为参数数量不足,
        // args 中就是空的了。
    }

 这一点在处理参数数量不确定的情况时会很方便。

 那个将接受的参数转为数组的参数名可以不写,只写一个 * 。这种情况下,在下面提到的 数组参数的展开 时就可以使用没有名字的 * 。

数组参数的展开

 可以将接受的数组展开,将里面的元素当作参数传到函数中。这种情况下,和 参数向数组的转换 一样,调用函数时在想要展开的参数表达式后面添加 '*' 就行了。指定了 '*' 的想要展开的表达式的结果必须是数组。

例:
    var args = [1, 2, 3, 4];
    func(args*);
    // args 中包含 1 2 3 4 这 4个元素,
    // 所以上面的调用和 func(1, 2, 3, 4); 具有相同效果。
    func(0, args*, 5);
    // 像这样把数组夹在其他参数的中间也是可以的。
    // 这样和 func(0, 1, 2, 3, 4, 5); 具有相同效果。


 不指定表达式,只写一个 * 当作参数的话,就可以将这个函数被调用的表达式所在的函数在声明时包含的没有名字的 '*' 参数传递到这个函数的 * 参数中。
例:
    function func(func_array, *)
    {
        // 经由 func_array 参数传入的函数数组中的函数,
        // 会按照他们在 func_array 数组中的位置顺序依次被调用,
        // 传入 func 的第二个以及之后的参数在各个函数被调用时
        // 也会以传进来时的状态传入这些函数。
        for(var i = 0; i < func_array.count; i++)
            func_array[i](i, *);
    }


 使用没有名字的 * 定义的函数在调用时会比使用有名字的数组参数的函数效率更高。

例:
    function func(ar*) { func2(ar*); }
    function func(*) { func2(*); }
    // 上面的两个函数的作用是完全一样的,但是下面的那个效率更高


 没有名字的 * 和“参数的省略”具有相同效果。以下的两个函数声明的效果是一样的。

例:
    function func() { func2(...); }
    function func(*) { func2(*); }