Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
guides:objects [2025-02-25 19:46] – Write about Maps versus Objects geek | guides:objects [2025-03-31 17:28] (current) – Move classes header to separate page geek | ||
---|---|---|---|
Line 218: | Line 218: | ||
; Some function you write using ObjOwnProps | ; Some function you write using ObjOwnProps | ||
ObjectProcessor1(someObject) { | ObjectProcessor1(someObject) { | ||
- | for key, value in ObjOwnProps(someObject) | + | for key, value in ObjOwnProps(someObject) |
MsgBox " | MsgBox " | ||
- | } | ||
} | } | ||
; Some function you write using object.OwnProps | ; Some function you write using object.OwnProps | ||
ObjectProcessor2(someObject) { | ObjectProcessor2(someObject) { | ||
- | try { | + | try for key, value in someObject.OwnProps() |
- | | + | MsgBox " |
- | MsgBox " | + | |
- | } | + | |
- | } | + | |
} | } | ||
Line 330: | Line 326: | ||
</ | </ | ||
- | ===== Fundamentals of Class Objects | + | ===== Classes |
- | ==== Function Objects ==== | + | See: [[guides: |
- | In AutoHotkey v1, there were several global collections of names that were kept separate. There was a collection of command names, a collection of label names, a collection of function names, and a collection of variable names. AutoHotkey v2 has mostly merged these collections, | ||
- | |||
- | Allowing functions to be saved inside variables and passed around like data is known as having [[https:// | ||
- | |||
- | <runner ahk2> | ||
- | MyFunction() { | ||
- | ; No matter how this function is called, the message box | ||
- | ; will say "You called MyFunction" | ||
- | MsgBox "You called " A_ThisFunc | ||
- | } | ||
- | |||
- | MsgBox IsObject(MsgBox) ", " Type(MsgBox) | ||
- | MsgBox IsObject(MyFunction) ", " Type(MyFunction) | ||
- | |||
- | MyVar := MyFunction ; Put MyFunction into a different variable | ||
- | MyVar() ; Call the function object stored inside MyVar | ||
- | </ | ||
- | |||
- | Function objects come inside global read-only variables by default, but can be passed around just like any other object. As shown above, it's easy to put the function object into a different variable even if the new variable has a different name. Additionally, | ||
- | |||
- | <runner ahk2> | ||
- | MyVar := () => MsgBox(" | ||
- | MyVar() | ||
- | |||
- | ; In AHKv2.1 this is allowed as well: | ||
- | ;MyVar2 := () { | ||
- | ; MsgBox "You called '" | ||
- | ;} | ||
- | ;MyVar2() | ||
- | </ | ||
- | |||
- | By itself, this syntax is usually seen when defining OnEvent type callbacks. It allows you to skip defining a function that might only be called in one place: | ||
- | |||
- | <code autohotkey> | ||
- | CloseCallback() { | ||
- | MsgBox "You tried to close the GUI" | ||
- | } | ||
- | g := Gui() | ||
- | g.OnEvent(" | ||
- | |||
- | ; Can be rewritten as: | ||
- | |||
- | g := Gui() | ||
- | g.OnEvent(" | ||
- | |||
- | ; Or in v2.1: | ||
- | |||
- | g := Gui() | ||
- | g.OnEvent(" | ||
- | MsgBox "You tried to close the GUI" | ||
- | }) | ||
- | </ | ||
- | |||
- | However, where things start to get really interesting is when you put function objects into //other objects//. Just like a function object can be stored inside a regular variable and then that variable becomes callable, a function object can be stored as an object property and then that property becomes callable. A callable property on an object is called a //method//. | ||
- | |||
- | When you call a function stored as an object property, AutoHotkey does a little trick with the parameter list. If you have '' | ||
- | |||
- | <runner ahk2> | ||
- | MyFunction(this, | ||
- | MsgBox 'a: ' a '`nb: ' b '`nc: ' c | ||
- | } | ||
- | |||
- | MyObject := { | ||
- | FunctionProperty: | ||
- | } | ||
- | |||
- | ; These following 4 lines are all equivalent | ||
- | MyObject.FunctionProperty(1, | ||
- | Temp := MyObject.FunctionProperty, | ||
- | (MyObject.FunctionProperty)(MyObject, | ||
- | MyObject.FunctionProperty.Call(MyObject, | ||
- | </ | ||
- | |||
- | ==== Prototyping ==== | ||
- | |||
- | AutoHotkey objects are *prototype* based, but AutoHotkey' | ||
- | |||
- | The first part of this arrangement was //function objects// being nested inside regular objects. The second part is // | ||
- | <runner ahk2> | ||
- | baseObject := { | ||
- | someProperty: | ||
- | } | ||
- | |||
- | testObject := { | ||
- | base: baseObject | ||
- | } | ||
- | |||
- | MsgBox testObject.someProperty ; Will show " | ||
- | </ | ||
- | |||
- | ==== Class Syntax ==== | ||
- | |||
- | AutoHotkey' | ||
- | |||
- | Class syntax is used to simultaneously define two things: a " | ||
- | |||
- | Remembering the fundamental of how functions stored in objects are called, it would mean that in this following example, when '' | ||
- | |||
- | <runner ahk2> | ||
- | testMethod(this, | ||
- | MsgBox "this Ptr: " ObjPtr(this) | ||
- | MsgBox 'a: ' a '`nb: ' b '`nc: ' c | ||
- | } | ||
- | MyClass := { | ||
- | Prototype: { | ||
- | | ||
- | } | ||
- | } | ||
- | |||
- | myObject := {base: MyClass.Prototype} | ||
- | |||
- | MsgBox " | ||
- | MsgBox " | ||
- | |||
- | myObject.functionProperty(1, | ||
- | </ | ||
- | |||
- | The "class object" | ||
- | |||
- | An instance factory is a function that creates instances of a class. An instance factory for an AHK class works something like this: | ||
- | |||
- | <code autohotkey> | ||
- | classFactory(someClass) { | ||
- | instance := {base: someClass.Prototype} | ||
- | instance.__Init() | ||
- | if HasMethod(instance, | ||
- | instance.__New() | ||
- | } | ||
- | return instance | ||
- | } | ||
- | </ | ||
- | The instance factory gets put onto the class object as its " | ||
- | <runner ahk2> | ||
- | testMethod(this, | ||
- | MsgBox 'a: ' a '`nb: ' b '`nc: ' c | ||
- | } | ||
- | classFactory(someClass) { | ||
- | instance := {base: someClass.Prototype} | ||
- | instance.__Init() | ||
- | if HasMethod(instance, | ||
- | instance.__New() | ||
- | } | ||
- | return instance | ||
- | } | ||
- | MyClass := { | ||
- | Prototype: { | ||
- | | ||
- | }, | ||
- | Call: classFactory | ||
- | } | ||
- | myInstance := MyClass() | ||
- | myInstance.functionProperty(" | ||
- | </ | ||
- | |||
- | This code invokes " | ||
- | |||
- | That's the vast majority of what class syntax does. In that last example, we manually created this class: | ||
- | |||
- | <runner ahk2> | ||
- | class MyClass { | ||
- | functionProperty(a, | ||
- | MsgBox 'a: ' a '`nb: ' b '`nc: ' c | ||
- | } | ||
- | } | ||
- | myInstance := MyClass() | ||
- | myInstance.functionProperty(" | ||
- | </ | ||
- | |||
- | When defining a class, it allows you to specify static and non-static properties. You can do exactly the same with the manually written code. Static properties get added to the class object. Non-static properties get added to the instance by the '' | ||
- | |||
- | <runner ahk2> | ||
- | class MyClass1 { | ||
- | static someProp := 123 | ||
- | someProp := 456 | ||
- | } | ||
- | myInstance1 := MyClass1() | ||
- | MsgBox " | ||
- | |||
- | ; Equivalent to | ||
- | |||
- | classFactory(someClass) { | ||
- | instance := {base: someClass.Prototype} | ||
- | instance.__Init() | ||
- | if HasMethod(instance, | ||
- | instance.__New() | ||
- | } | ||
- | return instance | ||
- | } | ||
- | MyClass2 := { | ||
- | Prototype: { | ||
- | | ||
- | }, | ||
- | Call: classFactory, | ||
- | someProp: 123 | ||
- | } | ||
- | myInstance2 := MyClass2() | ||
- | MsgBox " | ||
- | </ | ||
- | |||
- | === Unique behavior === | ||
- | |||
- | As mentioned previously, there are a few unique features of the '' | ||
- | |||
- | The first is // | ||
- | |||
- | The second difference is that the variable defined using '' |