# 简单对象 - 关联数组

AutoHotkey 的基本对象数据类型是关联数组, 特点是允许自定义它的行为. 默认情况下, 所有由 `{}`, `[]`, `Object()` 和 `Array()` 创建的对象支持以下内容:

方法:

- InsertAt / RemoveAt
- Push / Pop
- Delete
- MinIndex / MaxIndex / Length / Count
- SetCapacity / GetCapacity
- GetAddress
- _NewEnum
- HasKey
- Clone

属性:

- Base

函数:

- ObjRawGet
- ObjRawSet
- ObjGetBase
- ObjSetBase

弃用的(不推荐使用):

- Insert
- Remove

每个方法都有对应的函数(译者注: 这里描述的是以 "Obj" 为前缀的内置函数, 下文统称为 "Obj前缀函数"), 可用于传递由对象实现的任何自定义行为 -- 推荐这些 Obj前缀函数 仅用于此目的. 要调用某个这种函数, 在方法名前加上 "Obj" 前缀并把目标对象作为首个参数传递过去. 例如:

    array := [1, 2, 3]
    MsgBox % ObjMaxIndex(array) " = " array.MaxIndex()

如果对象的方法-函数的参数对象或值的类型不正确, 它将返回空字符串. 而独立函数如 ObjRawSet 则会抛出异常

## InsertAt [v1.1.21+]

插入一个或多个值到线性数组中的给定序号位置中.

    Object.InsertAt(Pos, Value1 , Value2, ... ValueN)

Pos

  要将 Value1 插入到数组中的序号数字. 随后的值将插入到 Pos+1, Pos+2, 等等.

Value1 ...

  要插入数组的一个或多个值. 要将另一个数组中的值一次性插入, 传递 `theArray*` 作为最后一个参数.

### 备注

InsertAt 对应的是 RemoveAt.

作为关联数组对象, Pos 的整数值同时也成为 Value1 在数组对象中的键名. 位于 Pos 之前或之后的键值对都会被自动改为正确的对应关系数值, 哪怕键对应的值不存在也是如此(因为对象是稀疏数组). 例如:

    x := []
    x.InsertAt(1, "A", "B") ; =>  ["A", "B"]
    x.InsertAt(2, "C")      ; =>  ["A", "C", "B"]

    ; 稀疏(不连续)/未赋值元素也被保留:
    x := ["A", , "C"]
    x.InsertAt(2, "B")      ; =>  ["A", "B",    , "C"]

    x := ["C"]
    x.InsertAt(1, , "B")    ; =>  [   , "B", "C"]

InsertAt 最好仅用于处理对象中的整数键表示线性数组中位置的情况. 如果对象中包含不连续的任意值整数键, 比如 ID(不连续的序号) 或 handles(句柄), InsertAt 会产生出乎意料的效果. 例如:

    x := [], handleX := 0x4321, handleY := 0x1234
    x.InsertAt(handleX, "A")
    MsgBox % x[handleX]  ; A - 正确
    x.InsertAt(handleY, "B")
    MsgBox % x[handleX]  ; 返回空值
    MsgBox % x[handleX+1]  ; 这是 "A" 新的 "位置"

InsertAt 不会影响文本或对象键, 所以可以安全的用于混合键类型的对象.

## RemoveAt [v1.1.21+]

从线性数组的指定位置移除键值对.

    Object.RemoveAt(Pos , Length)

Pos

  表示要从此处开始删除一个或多个值.

Length

  要删除值的范围. 从 `Pos` 到 `Pos+Length-1` 之间的所有值将被删除. 如果省略则仅删除 Pos 位置的值.

返回值

  如果省略 Length , 返回 Pos 对应的值(如果不存在值则返回空值). 其他情况则返回被删除的值中非空值的计数, 可用 Length 区别于稀疏数组, 但它总是返回 0 或 Length(包括0).

### 备注

RemoveAt 对应于 InsertAt.

剩下的那些位于 Pos 前后的键值对会根据 Length(或者省略时为 1) 长度强制对齐, 哪怕被删除的范围中不包含任何值. 例如:

    x := ["A", "B"]
    MsgBox % x.RemoveAt(1)  ; A
    MsgBox % x[1]           ; B

    x := ["A", , "C"]
    MsgBox % x.RemoveAt(1, 2)  ; 1
    MsgBox % x[1]              ; C

RemoveAt 最好仅用于处理对象中的整数键表示线性数组中位置的情况. 如果对象中包含不连续的任意值整数键, 比如 ID 或句柄, RemoveAt 会产生出乎意料的效果. 例如:

    x := {0x4321: "A", 0x1234: "B"}
    MsgBox % x.RemoveAt(0x1234) ; B
    MsgBox % x[0x4321]          ; 空
    MsgBox % x[0x4321-1]        ; A

RemoveAt 不会影响文本或对象键, 所以可以安全的用于混合键类型的对象.

## Push [v1.1.21+]

追加一个或多个值到数组的尾部.

    Object.Push( Value, Value2, ..., ValueN )

Value ...

  要插入数组的一个或多个值. 要将另一个数组中的值一次性插入, 传递 `theArray*` 作为最后一个参数.

返回值

  插入的最后一个值的位置(因为可能同时插入了多个值). 当数组仅包含负索引时可能为负数.

### 备注

如果数组为空或仅包含字符串或对象键时, 第一个插入的值的位置(索引) 为 1.

其他情况下, 插入的第一个值位于 `Object.MaxIndex() + 1`, 哪怕那个位置是负数或零. 如果这不是您预期的结果, 对于含有负数键的对象也可以这样 `Object.InsertAt(Object.Length() + 1, ...)` .

## Pop [v1.1.21+]

删除并返回数组中最后一个数组元素.

    Value := Object.Pop()

如果该数组中不含有任何元素, 返回值为空字符串. 其他情况下, 它相当于:

    Value := Object.RemoveAt(Object.Length())

## Delete [v1.1.21+]

删除对象中的键-值对.

    Object.Delete(Key)
    Object.Delete(FirstKey, LastKey)

Key

  任意一个键.

FirstKey, LastKey

  任意有效的整数范围或字符串键, 其中 FirstKey <= LastKey. 两个键必须是相同的类型.

返回值

  如果只有一个参数, 将返回被删除的值(如果不存在则返回空值). 其他情况将返回范围中存在并被删除的键的计数.

### 备注

与 RemoveAt 不同的是, Delete 不会影响任何没有被删除的键-值对(译者注: 仅删除值, 而保留键位). 例如:

    x := ["A", "B"]
    MsgBox % x.RemoveAt(1)  ; A
    MsgBox % x[1]           ; B

    x := ["A", "B"]
    MsgBox % x.Delete(1)    ; A
    MsgBox % x[1]           ; 为空

## MinIndex / MaxIndex [AHK_L 31+]

    MinIndex := Object.MinIndex()
    MaxIndex := Object.MaxIndex()

如果存在任何整数键, MinIndex 返回最小键值, 而 MaxIndex 返回最大键值. 其他情况返回空字符串.

    MsgBox % ["A", "B", "C"].MaxIndex()  ;  3
    MsgBox % ["A",    , "C"].MaxIndex()  ;  3
    MsgBox % {-10: 0, 10: 0}.MaxIndex()  ; 10
    MsgBox % {-10: 0, -1: 0}.MaxIndex()  ; -1
    MsgBox % {a: 1000, b: 0}.MaxIndex()  ;  空

## Length [v1.1.21+]

    Length := Object.Length()

返回从位置 1 开始的线性数组的长度; 也就是说, 对象包含的最大正整数键, 如果没有, 则为 0 .

    MsgBox % ["A", "B", "C"].Length()  ;  3
    MsgBox % ["A",    , "C"].Length()  ;  3
    MsgBox % {-10: 0, 10: 0}.Length()  ; 10
    MsgBox % {10: 10, 2: 20}.Length()  ; 10
    MsgBox % {-10: 0, -1: 0}.Length()  ;  0
    MsgBox % {a: 10, b: 200}.Length()  ;  0

## Count [v1.1.29+]

    Count := Object.Count()

返回对象中存在的键-值对的数量.

    MsgBox % {A: 1, Z: 26}.Count()    ;  2
    MsgBox % ["A", "B", "C"].Count()  ;  3
    MsgBox % ["A",    , "C"].Count()  ;  2

## SetCapacity [AHK_L 31+]

调整对象或其一个字段占用的内存空间.

    Object.SetCapacity(MaxItems)
    Object.SetCapacity(Key, ByteSize)

MaxItems

  对象在必须自动扩展前可以包含的键值对的最大数目. 如果少于键值对的当前数目, 则使用该数目并释放未使用的内存.

Key

  任何有效键.

ByteSize

  为目标字段字符串缓存设置新的大小, 不包括空终止符, 单位为字节. 如果字段不存在, 则创建它. 如果 ByteSize 为零, 则清空缓存但不移除空字段. 如果 ByteSize 小于当前大小, 则移除额外的数据; 否则保留所有现有的数据.

返回值

  成功时返回新设置的内存空间, 否则为空字符串.

## GetCapacity [AHK_L 31+]

    MaxItems := Object.GetCapacity()
    ByteSize := Object.GetCapacity(Key)

返回对象或其一个字段当前占用的内存空间.

如果字段不存在或不包含字符串, 则返回空字符串.

## GetAddress [AHK_L 31+]

    Ptr := Object.GetAddress(Key)

返回对象的区域字符串缓冲区地址, 如果它有.

## NewEnum [AHK_L 49+]

    Enum := Object._NewEnum()

返回一个新的枚举器用于枚举当前对象中的键值对. 该方法通常不直接调用, 而是使用 for 循环来遍历对象.

## HasKey [AHK_L 53+]

    Object.HasKey(Key)

只要 Object 中 Key 关联的值(即使值为 "") 存在(已定义) 就返回真 true, 否则为假 false.

## Clone [AHK_L 60+]

    Clone := Object.Clone()

返回对象的一个浅拷贝(拷贝对象的指针, 而不是对象本身, 引用的内存地址资源相同, 对象引用加 1).

## Base

检索或设置对象的基对象.

    BaseObject := Object.Base

    Object.Base := BaseObject

BaseObject 必须是对象或空字符串.

基对象定义的属性和方法只有在使用该基对象时才可访问. 因此, 更改 对象 的 base 也会改变可用属性和方法的集合.

参见: ObjGetBase(), ObjSetBase

## ObjRawGet [v1.1.29+]

在 Object(对象) 中检索给定键所关联的值.

    Value := ObjRawGet(Object, Key)

如果 Object 不包含 Key, 则返回空字符串. 没有元-函数或属性函数被调用. Object 的基对象的内容是不被考虑的, 因为 base 本身是一个属性, 而不是默认的键-值对, 所以它通常不会返回值.

如果 Object 是不正确的类型, 则抛出异常.

## ObjRawSet [v1.1.21+]

存储或覆盖对象中的一组键值对.

    ObjRawSet(Object, Key, Value)

这个函数提供一种绕过 __Set 元函数和属性的途径. 如果不是必须的, 最好还是使用普通的(赋值) 方法. 例如: `Object[Key] := Value`

由于目的是绕过元函数, 所以它只是一个函数, 而不是(对象的) 方法. 因为调用(对象的) 内建方法, 通常也会调用 __Call 元函数.

如果 Object 是不正确的类型, 则抛出异常.

## ObjGetBase [v1.1.29+]

返回对象的基对象.

    BaseObject := ObjGetBase(Object)

没有元-函数被调用. 即使键 "base" 已经存储在对象中(如使用 ObjRawSet 或 SetCapacity) 也会返回对象的 base. 如果对象没有 base, 则返回空字符串.

如果 Object 是不正确的类型, 则抛出异常.

参见: Base property

## ObjSetBase [v1.1.29+]

设置对象的基对象.

    ObjSetBase(Object, BaseObject)

没有元-函数被调用. 即使键 "base" 已经存储在对象中(如 ObjRawSet 或 SetCapacity) 也会返回对象的 base. 如果对象没有 base, 则返回空字符串.

如果 Object 是不正确的类型或如果 BaseObject 不是对象或空字符串, 则抛出异常.

参见: Base property

## Insert [AHK_L 31+]

弃用的: Insert 不推荐在新脚本中继续使用. 可以用 InsertAt, Push, ObjRawSet 或简单赋值操作替代它.

插入键值对到对象中, 如果传递的是整数键, 将自动调整现有的键.

    Object.Insert(Pos, Value1 , Value2, ... ValueN )
    Object.Insert(Value)
    Object.Insert(StringOrObjectKey, Value)

Insert 的行为取决于参数的个数和类型::

- 如果传递多个参数且第一个参数为整数, Insert 的行为类似 InsertAt.
- 如果传递多个参数且第一个参数不是整数, Insert 的行为类似 ObjRawSet.
- 如果仅有一个参数, Insert 的行为类似 Push.

Insert 返回 true. 从 [v1.1.21] 开始, 当内存申请失败时将抛出异常. 之前的版本返回一个空字符串.

## Remove [AHK_L 31+]

弃用的: Remove 不推荐在新脚本中继续使用. 可以用 RemoveAt, Delete 或 Pop 替代.

从对象中删除键值对.

    Object.Remove(FirstKey, LastKey)

Remove 的行为方式取决于参数的个数和类型:

- `Object.Remove(Integer)` 表现得就像 `Object.RemoveAt(Integer)`.
- `Object.Remove(Integer, "")` 表现得就像 `Object.Delete(Integer)`.
- `Object.Remove(Integer1, Integer2)` 表现得就像 `Object.RemoveAt(Integer1, Integer2 - Integer1 + 1)`.
- `Object.Remove()` 表现得就像 `Object.Pop()`.
- 其他任何合法的调用时, 表现得就像 Delete.

dftg