< / >

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];
            }
        }
    }