# 函数对象

"函数对象" 通常表示以下任何一项:

- Func 或 Closure 对象, 它表示一个实际的函数; 可以是内置函数也可以是脚本定义的函数.
- 用户定义的对象, 可以像函数一样调用. 亦称为 "函数子".
- 任何其他可以像函数一样调用的对象, 如绑定函数对象或 COM 方法返回的 JavaScript 函数对象.

函数对象可用于以下情况:

- CallbackCreate
- Gui 事件
- For ... in
- HotIf
- Hotkey
- Hotstring
- InputHook (OnEnd, OnChar, OnKeyDown, OnKeyUp)
- Menu.Add
- OnClipboardChange
- OnError
- OnExit
- OnMessage
- RegEx callouts
- SetTimer
- Sort

要确定一个对象是否可被调用, 请使用以下方法之一:

- 默认情况下, `Value.HasMethod()` 适用于所有的 AutoHotkey 值和对象, 但对于某些对象或类, 允许重写 HasMethod. 对于 COM 对象, 这通常会失败(抛出异常或产生错误的结果), 除非该 COM 对象实际上是来自其他进程的 AutoHotkey 对象.
- `HasMethod(Value)` 适用于所有的 AutoHotkey 值和对象, 并且不能被重写, 但如果不能确定 Call 方法的存在, 则返回 false. An exception is thrown if Value is a ComObject.

## 用户自定义

用户定义的函数对象必须包含一个 "函数" 实现的 Call 方法定义.

    class YourClassName {
        Call(a, b) {  ; 按需声明参数, 或 array*.
            ;...
            return c
        }
        ;...
    }

这适用于 YourClassName 的 实例, 例如由 `YourClassName()` 返回的对象. 用 `static Call` 代替 `Call` 将覆盖 YourClassName 本身被调用时的情况.

### 示例

下面的例子定义了一个可以被调用的函数数组; 当被调用时, 它依次调用数组中的每个元素.

    class FuncArrayType extends Array {
        Call(params*) {
            ; 调用函数列表.
            for fn in this
                fn(params*)
        }
    }

    ; 创建一个函数数组.
    funcArray := FuncArrayType()
    ; 向数组中添加函数(可以在任何位置完成).
    funcArray.Push(One)
    funcArray.Push(Two)
    ; 创建一个使用数组作为方法的对象.
    obj := {method: funcArray}
    ; 调用方法(One 和 Two 都会被调用).
    obj.method("2nd")
    ; 将其作为函数调用.
    (obj.method)("1st", "2nd")

    One(param1, param2) {
        ListVars
        MsgBox
    }
    Two(param1, param2) {
        ListVars
        MsgBox
    }

## 绑定函数对象

行为像函数, 但只是将预定义的参数传递给另一个函数.

有两种建立绑定函数对象的方式:

- 通过调用 Func.Bind 方法, 其绑定参数值至一个函数.
- 通过调用 ObjBindMethod 函数, 其绑定参数值和方法名至目标对象.

可以调用绑定函数对象, 如下例所示. 当绑定函数对象被调用时, 它调用绑定的函数或方法, 传递绑定的参数和后面跟着的调用者传递的任何参数. 未绑定的参数位置是从调用者的参数列表中指定的位置(从左到右). 例如:

    fn := RealFn.Bind(1)  ; 只绑定第一个参数
    fn(2)    ; 显示 "1, 2"
    fn.Call(3) ; 显示 "1, 3"

    fn := RealFn.Bind( , 1)  ; 只绑定第二个参数
    fn(2)        ; 显示 "2, 1"
    fn.Call(3) ; 显示 "3, 1"
    fn(, 4)     ; 错误: 'a' 被省略了

    RealFn(a, b, c:="c") {
        MsgBox a ", " b
    }

ObjBindMethod 可用于绑定方法, 即使是在无法检索到方法本身的引用时. 例如:

    Shell := ComObject("Shell.Application")
    RunBox := ObjBindMethod(Shell, "FileRun")
    ; 显示运行对话框.
    RunBox

更多复杂的例子, 请参阅 SetTimer.

其他的属性和方法都是从 Func 继承过来的, 但不反映目标函数或方法的属性(不需要作为一个函数来实现). BoundFunc 作为一个匿名的变量函数, 没有其他形式上的参数, 类似于下面的胖箭头函数:

    Func_Bind(fn, bound_args*) {
        return (args*) => (args.InsertAt(1, bound_args*), fn(args*))
    }

dftg