# 函数对象

"函数对象" 泛指以下内容:

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

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

- GUI 控件事件(G-标签)
- 热键
- 菜单
- OnClipboardChange()
- OnExit()
- OnMessage()
- SetTimer

## 用户定义的函数对象

用户定义函数对象应遵循以下一般模式:

    class YourClassName {
        Call(a, b) {  ; 根据需要声明参数, 或数组*.
            ;...
        }
        __Call(method, args*) {
            if (method = "")  ; 对 %fn%() 或 fn.()
                return this.Call(args*)
            if (IsObject(method))  ; 如果此函数对象作为方法被使用.
                return this.Call(method, args*)
        }
        ;...
    }

模式中各个部分适用于不同的使用情形, 如下:

- 如果脚本按 %this%() 或 `this.()` 的形式调用, 则, `method`(方法名) 的值是空字符串.
- 如果对象作为方法被调用, 则 `IsObject(method)` 返回真, 并且 `method` 包含关于目标对象的引用. 如: 若 `x.y` 指向 `this` 函数对象, 则 `x.y()` → `this[x]()` → `this.__Call(x)` → `this.Call(x)`.
- [v1.1.20+]: 如果对象被某需要回调函数的内置函数所使用, 如 OnMessage() 或 SetTimer, 则此对象仅需支持 Call 方法即可.

上述过程可以直接在 __Call 中完成, 推荐使用 __Call 代替 Call 以便更好的迁移到 AutoHotkey v2 版本, 其会改变 `%this%()` 的行为及调用 CALL 的方法调用.

### 示例

如果要定义多个函数对象类型, 则应将样板代码委托给基类(但如果您要将代码与其他人的组合使用, 请小心冲突). 例如:

    class FunctionObject {
        __Call(method, args*) {
            if (method = "")
                return this.Call(args*)
            if (IsObject(method))
                return this.Call(method, args*)
        }
    }

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

    ; 此示例需要上面的 FunctionObject class 才能工作.
    class FuncArrayType extends FunctionObject {
        Call(obj, params*) {
            ; 调用函数列表.
            Loop % this.Length()
                this[A_Index].Call(params*)
        }
    }

    ; 创建一个函数数组.
    funcArray := new FuncArrayType
    ; 向数组中添加函数(可以在任何位置完成).
    funcArray.Push(Func("One"))
    funcArray.Push(Func("Two"))
    ; 创建一个使用数组作为方法的对象.
    obj := {method: funcArray}
    ; 调用方法.
    obj.method("foo", "bar")

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

## 绑定函数对象[v1.1.20+]

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

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

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

调用绑定函数对象, 如下例所示. 不支持其他方法. 当绑定函数对象被调用时, 它调用绑定的函数或方法, 传递绑定的参数和后面跟着的调用者传递的任何参数. 例如:

    fn := Func("RealFn").Bind(1)

    %fn%(2)    ; 显示 "1, 2"
    fn.Call(3) ; 显示 "1, 3"

    RealFn(a, b) {
        MsgBox %a%, %b%
    }

ObjBindMethod() 用于绑定无法引用的方法. 例如:

    file := FileOpen(A_ScriptFullPath, "r")
    getLine := ObjBindMethod(file, "ReadLine")
    MsgBox % %getLine%()  ; 显示此文件的第一行.

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

dftg