< / >

This is a blog by about coding and web development.

AS3 and Proxy

Posted on in

In ActionScript 3, you can extend a class from the Proxy class to override the behavior of many language level operations, making it a valuable tool for advanced development. However, they are much slower than sealed classes, so be careful with their use when high performance is necessary.

Proxy allows you to override:

// function calls
foo.bar(1, 2)
=>
foo.callProperty('bar', 1, 2)

// property get
foo.bar
foo['bar']
=>
foo.getProperty('bar')

// property set
foo.bar = 123
foo['bar'] = 123
=>
foo.setProperty('bar', 123)

// property delete
delete foo.bar
delete foo['bar']
=>
foo.deleteProperty('bar')

// in operator
'bar' in foo
=>
foo.hasProperty('bar')

// descendant operator
foo..bar
=>
foo.getDescendants('bar')

Proxy also allows you to override the handling of for..in and for each..in loops, using the nextNameIndex, nextName, and nextValue methods. This for..in loop:

for (var key:String in foo) {
    trace(key);
}

on a proxy, is equivalent to:

var i:int = 0;
while (true) {
    var index:int = foo.nextNameIndex(i);
    if (index == 0)
        break;
    var key:String = foo.nextName(index);
    trace(key);
    i++;
}

Similarly, this for each..in loop:

for each (var value:* in foo) {
    trace(value);
}

on a proxy, is equivalent to:

var i:int = 0;
while (true) {
    var index:int = foo.nextNameIndex(i);
    if (index == 0)
        break;
    var value:* = foo.nextValue(index);
    trace(value);
    i++;
}

Here is an example stub class implementing these methods:

package {
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    public class ExampleProxy extends Proxy {
        private var items:Array;

        public function ExampleProxy():void {
            items = [];
        }

        override flash_proxy function deleteProperty(name:*):Boolean {
            return delete items[name];
        }

        override flash_proxy function getProperty(name:*):* {
            return items[name];
        }

        override flash_proxy function hasProperty(name:*):Boolean {
            return name in items;
        }

        override flash_proxy function nextNameIndex(index:int):int {
            if (index > items.length)
                return 0;
            return index + 1;
        }

        override flash_proxy function nextName(index:int):String {
            return String(index - 1);
        }

        override flash_proxy function nextValue(index:int):* {
            return items[index - 1];
        }
    }
}