Can I use apply() with constructor to pass arbitra

2019-01-19 02:56发布

I've got a function wich can accept a varible number of parameter with a rest operator.

I want create an object passing the argument collected with the rest operator directly to a constructor without create an object and call an initializing function and without passing the entire array but the parameters ah I do with apply() function.

Is it possible ? Using apply doesn't work.

public function myFunc(...arg) {

     // something link "new MyClass.apply(args)"
     return new MyClass();

}

4条回答
戒情不戒烟
2楼-- · 2019-01-19 03:19

Well this led me to an interesting long research!

I found this neat SWC file filled with utils for mimicking the AS2 eval(): http://www.riaone.com/products/deval/index.html

And here's a proof of concept that what you're looking for might actually work:

package tests {
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.utils.getQualifiedClassName;
    import r1.deval.D;

    public class RandomTests extends Sprite{

        public function RandomTests() {
            super();

            var test:BitmapData =   create(BitmapData, 100, 100, true, 0x00000000);
            trace(test);
        }


        public function create( pClass:Class, ... pArgs ):* {
            D.importClass(pClass);
            var fullQName:String =  getQualifiedClassName(pClass);
            var qNameSplit:Array =  fullQName.split("::");
            var className:String =  qNameSplit[1];
            fullQName =             qNameSplit.join(".");

            var statements:String =
            "import $0;\n" +
            "return new $1($2);";


            var args:Array =        [];
            for (var a:int = 0, aLen:int = pArgs.length; a < aLen; a++) {
                switch(pArgs[a].constructor) {
                    case String:
                        args[a] =   "\"" + pArgs[a] + "\"";
                        break;
                    default:
                        args[a] =   pArgs[a];
                        break;
                        //throw new Error("Unhandled type, please add it: " + pArgs[a].constructor);
                }
            }

            return D.eval(XString.gsub(statements,[fullQName, className, args.join(",")]));
        }
    }

}

Sorry for the bits of dependencies (Like my XString class for easy sub-replacements) but it does work in theory. The only issue would be passing object references as argument entries. But then again... the r1.deval.D class might be able to take it... hmm.

Anyways, thought maybe this would be worth sharing.

查看更多
欢心
3楼-- · 2019-01-19 03:20

Unfortunately no. There is no way to make apply work for constructor. What is done generally is to prepare a number of call based on the number of arguments :

public function myFunc(...arg):Myclass {
  switch (arg.length) {
    case 0:return new MyClass();
    case 1:return new MyClass(arg[0]);
    case 2:return new MyClass(arg[0], arg[1]);

    //... etc

    case n:return new MyClass(arg[0], arg[1],..,arg[n]);
    default: throw new Error("too much arguments in myFunc");
  }
}
查看更多
淡お忘
4楼-- · 2019-01-19 03:29

well there's also this

public function myFunc(args:Object) {

   //then access various argumens
   return new MyClass(args.name, args.id, args.active)

}

and call it through myFunc({id:33,name:'jo')

you could then pass the object, or is this too far from what you're looking for?

查看更多
Melony?
5楼-- · 2019-01-19 03:40

I'm searching for the answer too, but too sad to see the answer is no....

Here's my current (not so good) way to do this kind of stuff, hope some of you interest:

// Foo.as
public class Foo {
    // construct
    public function Foo(... args):void {
        create.apply(this, args);
    }

    // this function do as a really construct function, tricky stuff
    function create(id:uint, name:String) {
        trace(id, name);
    }
}

// Bar.as
// for create this kind of class, just new it as usual
...
var foo:Foo = new Foo(123, "abc");
...
查看更多
登录 后发表回答