I am new to ActionScripting but I have done some Java. I was told they are kinda similar. I am coding my swf file with some AS3 integrated.
function init():void{
// do something
}
function init(var string:String):String{
// do something else
}
is this not allowed in AS? If not, is there another way of handling it besides?
Thanks in advance.
Yes, you can override functions. But the example you gave is not overriding - it's overloading. For overriding a function, you basically just create a function with the same signature and everything in a subclass and add the word "override" right before it.
You can't directly overload a function though. If you want a variable number of parameters, you have to use optional parameters instead. Like this:
function init(str:String = null):String
{
if (str == null)
{
// do one thing
return null;
}
else
{
// do another thing
return "someString";
}
}
And that's about the best you're going to be able to do in AS3. The inability to overload functions, at least strictly speaking, is a fairly common complaint and obvious shortcoming of the language.
Do you mean method overloading? Actionscript, sadly, does not support this.
To get around it, you can use default parameters, or just make your parameters a bit less constraining. This answer has some details on that.
You could try this:
function init(var string:String = "Default value"):String{
// do something
}
Actionscript does not support method overloading. However, based on the answer to this question you have other options.
If you just want to be able to accept any type, you can use * to
allow any type:
function someFunction( xx:*, yy:*, flag:Boolean = true )
{
if (xx is Number) {
...do stuff...
} else if (xx is String) {
...do stuff...
} else {
...do stuff...
}
}
If you have a large number of various parameters where order is
unimportant, use an options object:
function someFunction( options:Object )
{
if (options.foo) doFoo();
if (options.bar) doBar();
baz = options.baz || 15;
...etc...
}
If you have a variable number of parameters, you can use the ...
(rest) parameter:
function someFunction( ... args)
{
switch (args.length)
{
case 2:
arr = args[0];
someBool = args[1];
xx = arr[0];
yy = arr[1];
break;
case 3:
xx = args[0];
yy = args[1];
someBool = args[2];
break;
default:
throw ...whatever...
}
...do more stuff...
}
For cases where you need to call a common function to a number of
classes, you should specify the interface common to each class:
function foo( bar:IBazable, flag:Boolean )
{
...do stuff...
baz = bar.baz()
...do more stuff...
}
Related
I have a set of get functions in JS such as:
get UserName() {
return this.userModel.Name;
}
I want the ability to check if the function exist before I call it.
I tried:
if (this.UserName == 'function')...
but it's always false, since userModel.name is a string, typeof UserName returns 'string' type and not a 'function'.
any idea how I can accomplish this ?
One simple way to check that UserName exists (without calling the getter) is to use in:
if ('UserName' in this) {
// this.UserName is defined
}
If you need a stronger check where you directly access the getter function, use Object.getOwnPropertyDescriptor:
var userNameDesc = Object.getOwnPropertyDescriptor(this, 'UserName');
if (userNameDesc && userNameDesc.get) {
// this.UserName is definitely a getter and is defined
}
You can use Object.getOwnPropertyDescriptor() which returns basically the same data structure that is fed to Object.defineProperty() like this:
let descriptor = Object.getOwnPropertyDescriptor(this, "UserName");
if (descriptor && typeof descriptor.get === "function") {
// this.UserName is a getter function
}
Or, if you want more granular info, you can do this:
let descriptor = Object.getOwnPropertyDescriptor(this, "UserName");
if (!descriptor) {
// property doesn't exist
} else if (typeof descriptor.get === "function") {
// this.UserName is a getter function
} else if (typeof descriptor.value === "function") {
// property directly contains a function (that is just a regular function)
} else {
// property exists, but it does not have a getter function and
// is not a regular function
}
You can also test many other properties of the descriptor such as value, set, writable, configurable, enumerable as described here on MDN.
Is there a way to declare a function such that I don't care about return value? For example I have this Array extension:
extension Array {
func forEach(function: (element: T) -> ()) {
for e in self {
function(element: e)
}
}
}
Now I want to do:
textFields.forEach{$0.resignFirstResponder()}
And I can't because the function is declared to return Void.
This would fix it:
textFields.forEach{$0.resignFirstResponder();return}
But is there a generic way to declare the function such that I can return any value or Void?
Thanks!
If you add a second generic parameter with no constraints, and type the function to return it, then any return value would be accepted:
extension Array {
func forEach<U>(function: (Element) -> U) {
for e in self {
function(e)
}
}
}
func f(i: Int)->Int {
return i * 2
}
func g(i: Int) -> Double {
return Double(0.0)
}
func h(i: Int) {
println("\(i)")
}
let a = [1,2,3]
a.forEach(g) // U will be an Int
a.forEach(f) // U will be a Double
a.forEach(h) // U will be a ()
However, I’d strongly suggest you not do this and use for…in instead.
The only purpose of running a function on an array but not using the return value is for side-effects. When writing in a more imperative style and using side-effects and external state (as opposed to a more declarative functional style) it’s much better to use for…in as a signal that this is what you’re doing.
There are also unpleasant gotchas involved in constructing your own pseudo-control structures. For example, think about this:
// function that does something side-effecty, but
// if it achieves some goal, exist early
func someFunc(a: [Int]) {
a.forEach { i -> () in
// goal achieved early,
// return from func
return
}
assert(false)
}
This is a common practice – cut out of a function early if some goal (or failure) is achieved. But with the forEach structure this is a bit misleading. It looks like a regular loop, but it’s actually a closure, and the return returns from that closure, ready for forEach to call the next one (essentially, it behaves like a continue in a regular loop).
Use map():
let textFields : [UITextField] = [] // or whatever
textFields.map{$0.resignFirstResponder()}
This way you don't have to specify the return type, and you don't need to reinvent map with your forEach extension.
I tried custom functions:
if(Input.GetMouseButtonUp(0)) {
AcceptInput = true;
targetScript.enabled = false;
changeSprite ();
}
function changeSprite () {
//other stuff
}
It had an error:
Assets/Scripts/Button.js(70,1): BCE0070: Definition of 'Button.changeSprite()'
depends on 'Button.changeSprite()' whose type could not be resolved because of
a cycle. Explicitly declare the type of either one to break the cycle.
I don't get what's wrong with the function. can any body help me?
As the error message tells us, you can try defining the return type of the function, in this case "void";
function changeSprite(): void {
//other stuff
}
very new to SharedObjects, but essentially all I want to do is let a user answer a question once and not allow them to answer again, how is it possible. This is what I have below?
/*if(_question.data.seenQuestion == "true") {
cookie_txt.text = "COOKIE FOUND";
} else {
cookie_txt.text = "NO COOKIES";
}*/
var _question:SharedObject;
_question.data.seenQuestion = "true";
_question.flush();
_question.close();
You're very close. It looks like you're not actually creating a SharedObject, to do that you would use the method getLocal:
var _question:SharedObject = SharedObject.getLocal("questionData");
Additionally, since SharedObject supports primitive types (String, int, Number, Object, Boolean, etc), you should store a Boolean instead of a String:
if(_question.data.seenQuestion)
{
cookie_txt.text = "COOKIE FOUND";
}
else
{
cookie_txt.text = "NO COOKIES";
}
_question.data.seenQuestion = true;
_question.flush();
Lastly, if you're using a local shared object (more common), you don't need to call close().
You do need to create your SharedOBject or else your code will throw errors:
var _question:SharedObject = SharedOBject.getLocal("myapp");
No need for flush or close just assign/change some data and that's it.
_question.data.seenQuestion = "true";
However SharedObject is not a good solution for persistent data. User can erase it/reset it, etc ...
Why do you think the code below does not work?
What would you change/add to make it work?
Any help is appreciated..
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function, ...args):void
{
bb(f, args);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:Array = null;
function bb(f:Function, ...args):void
{
func = f;
argum = args;
exec();
}
function exec()
{
func.apply(null, argum);
}
I get an ArgumentError (Error #1063):
Argument count mismatch on test_fla::MainTimeline/TraceIt(). Expected 2, got 1.
..so, the passed parameter (argum) fails to provide all passed arguments..
..Please keep the function structure (traffic) intact.. I need a solution using the same functions in the same order.. I have to pass the args to a variable and use them in the exec() method above..
regards
Ok, here is the solution.. after breaking my head : )
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function=null, ...args):void
{
var newArgs:Array = args as Array;
newArgs.unshift(f);
bb.apply(null, newArgs);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:*;
function bb(f:Function=null, ...args):void
{
func = f;
argum = args as Array;
exec();
}
function exec():void
{
if (func == null) { return; }
func.apply(this, argum);
}
This way, you can pass arguments as variables to a different function and execute them..
Thanks to everyone taking the time to help...
When TraceIt() eventually gets called, it's being called with 1 Array parameter, not a String and int parameters.
You could change TraceIt() to:
function TraceIt(args:Array)
{
trace(args[0], args[1]);
}
Or you could change exec() to:
function exec()
{
func.apply(null, argum[0].toString().split(","));
}
...as it appears when you pass "test", 1, you end up with array whose first value is "test,1". This solution doesn't work beyond the trivial case, though.
Change your bb function to look like this:
function bb(f:Function, args:Array):void
{
func = f;
argum = args;
exec();
}
As you have it now, it accepts a variable number of arguments, but you are passing in an array(of the arguments) from aa.