Function call(thisArg:*, ... args) first parameter usage in actionscript - actionscript-3

what does call(thisArg:*, ... args) first parameter mean?
Assuming f() is defined in a unnamed package as global function, following is the code snippet:
package {
public function f(message:String):void {
trace(message);
trace(this.watchedValue);
}
}
test code as following:
public function test():void {
var obj:Object = {watchedValue:100};
f("invoking f");
f.call(obj, "invoking f by call()");//actual result is undefined, but shouldn't be 100?
}

This param only used in closures and anonymous functions, like
var testFunc:Function = function():void{trace(this.watchedValue)}
EDIT:
in you case it will be
package {
public var f:Function = function(message:String):void {
trace(message);
trace(this.watchedValue);
}
}
EDIT2
first parameter of call will be this in called function. This is the way to call fauction like a method of object.
But when function is method or top level function first parameter of call() will be ignored. To use first param your function must be variable with anonymous function.

As far as I know Function.call() is the same as function(), except the fact you change the scope of this. Normally this referrers to the current class, but it could be another class. \
Your test function looks wrong, it should be obj instead of o
public function test():void {
var obj:Object = {watchedValue:100};
f("invoking f");
f.call(obj, "invoking f by call()");
}

Related

Action Script Convert Function to an Object

I need to convert a function to an object. For example, when I need to use the variable called fn I want to be able to use it as a function fn() or as an object fn.json(). I have code to do it, but I think it's not correct.
package lib.smartic {
// import
import lib.smartic.smartic;
// constructor $
public var fn = function(s):smartic{
return new smartic(s);
};
Function.prototype.json = function (s) {
// call
};}
How can I apply the prototype to my variable fn, not just to the object class?
Actually, Function is an Object... and as said #The_asMan, you shouldn't use prototypes.
Simple example:
var smartic: Smartic = new Smartic("someValue");
trace(smartic.json());
And definition of your Smartic class, without prototypes:
public class Smartic {
private var _value:String;
public function Smartic(value:String) {
_value = value;
}
public function json():String {
return "Some json here";
}
}
I don't know what you want to do exactily but if you want smartic to be a function you can do something like this:
keep the code givent by Nicolas Siver and add this function:
public function smarticFunc(value:String):Smartic
{
return new Smartic(value);
}
so you can use smarticFunc as function or as Smartic as it returns a Smartic.

Referencing own constructor in inner function

Here's a toy example distilled from a complex class:
public class MyClass {
public function MyClass() {
trace('Created');
}
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
var object:MyClass = new MyClass(); // line 10
callback(object);
}
}
}
After calling the static function:
MyClass.makeObjectAsync(function(object:Myclass):void { ... })
the following run-time exception occurs at line 10:
TypeError: Error #1007: Instantiation attempted on a non-constructor.
Why is this, and what can I do about it?
Edit
It appears that new (MyClass)() works. Now I'm possibly more confused.
Not too clear on the WHY to be honnest. It has to do with the scope inherited by anonymous functions, depending on how they are declared.
I have 2 solutions for you though.
If your makeObject method was not static, it would work.
Declare your anonymous function the other way :
public static function makeObjectAsync(callback:Function):void {
var inner : Function = function():void {
var object:MyClass = new MyClass();
callback(object);
};
inner();
}
You shouldn't call your variable "object". Why do you nested your inner function? Why don't you just:
public static function makeObjectAsync(callback:Function):void {
callback(new MyClass());
}
Or if you really want that nested function:
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
callback(new MyClass());
}
}
And you can't recall the class' constructor again, use a function which is called in the constructor then call it again. With this you aren't referencing the constructor but creating a new instance of the class.

How can I pass all parameters (one by one) in an object to a constructor in AS3?

This is a hard question to do, but I'll try to explain.
I have the Class and the parameters of its contructor as an object. What I need to do is a function that returns an instance of this class, passing this parameters to the constructor.
This is the code:
Some random and unmodifiable class:
public Foo {
public function Foo(a:int, b:String) {
// constructor
}
}
And some function (in some another class):
function bar(params:Object):* {
var baz:Foo = new Foo(params.a, params.b);
return baz;
}
What I need to do is make this function generic, without pass params as parameter to Foo constructor because I can't modify it. Something like:
function bar2(clazz:Class, params:Object):* {
var baz:* = new clazz(/*some magic way to transform params in comma separated parameters*/);
return baz;
}
Anyone can help me?
Thanks a lot.
This is called parameterized factory. First I thought about Function.apply, but it doesn't apply to constructors (he-he). So, people are making factories like this:
function create(what:Class, args:Array):* {
switch (args.length) {
case 0: return new what();
case 1: return new what(args[0]);
case 2: return new what(args[0], args[1]);
...
//PROFIT!
}
throw new Error("Need moar cases!");
}
what about using ByteArrayto copy the object ?
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
newObjectCopy = clone(originalObject);
source
If you have the option of not using a constructor, but adding an initialise() function to each class which can be constructed instead, you could use Function.apply - something like in the example below.
public class ThingCreator
{
public static function createTheThing(c:Class, params:Array):Object
{
var the_thing:Object = new c();
the_thing.initialise.apply(the_thing, params);
return the_thing;
}
}
As alxx pointed out above, Function.apply and AS3 reflection in this case does not seem to work with AS3's constructors.

AS3 - Can I have access to the object (or function) who call me?

I've asked this same question with Python.
Now I like to know if this can be done in AS3.
If I have something like this:
package
{
public class SomeClass
{
private function A():void { C() }
private function B():void { C() }
private function C():void
{
// who is the caller, A or B ???
}
public function SomeClass()
{
A()
B()
}
}
}
Despite the design or other issues, this is only a question of an inquiring mind.
Note: I like to have an access to an instance of the caller function so I can call that caller function (if I want to)
Note 2 : This has to be done without changing function C() signature
"Unlike previous versions of ActionScript, ActionScript 3.0 has no arguments.caller property. To get a reference to the function that called the current function, you must pass a reference to that function as an argument."
From http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/arguments.html
That's the only way you can do that, otherwise you'll need to make a global variable to tell what function is calling C
Sure it can be done. You can do something like
private function C():void
{
var e:Error = new Error();
var stack:String = e.getStackTrace();
//analyze stack and find out which function called it.
}
this is ugly but it would work.

Unrolling var args in AS3

I'm wondering if there is some way to unpack a variable length argument list in AS3. Take for example this function:
public function varArgsFunc(amount:int, ...args):Array
{
if (amount == 3)
{
return args
}
else
{
return varArgsFunc(++amount, args)
}
}
If I call this:
var result:Array = varArgsFunc(0, [])
result now contains a nested set of arrays:
[[[[]]]]
The problem here is that the args parameter is treated as an array. So if i pass it onto a function with a variable argument list, it will be treated as a single argument.
In Scala there is the :_* operator that tells the compiler to break apart a list into a list of parameters:
var list:Array = ['A', 'B', 'C']
// now imagine we have this class, but I would like to pass each list element
// in as a separate argument
class Tuple {
public function Tuple(...elements)
{
// code
}
}
// if you do this, the list will become be passed as the first argument
new Tuple(list)
// in scala you can use the :_* operator to expand the list
new Tuple(list :_*)
// so the :_* operator essentially does this
new Tuple(list[0], list[1], list[2])
I would like to know if a technique/operator exists in AS3 to expand an array into an argument list.
The apply() method on all functions lets you pass in the arguments in an array instead of the "normal" way.
package {
import flash.display.Sprite;
public class Foo extends Sprite {
public function Foo() {
var args:Array = ["a", "b", "c"];
// "normal" call
varArgsFunc(args);
// what you wanted:
varArgsFunc.apply(null, args);
}
public function varArgsFunc(...args):Array {
trace("got", args);
}
}
}
As a side note to this answer
The original question was not only passing the "unrolled" ...args using the super but to also pass a regular variable first
public function varArgsFunc(amount:int, ...args):Array
If this was the actual method being called the code would be
public function varArgsFunc(amount:int, ...args):Array
{
super.varArgsFunc.apply(this, [amount].concat(args));
}