i have the following question:
var a = 1;
function b(){
a = 10;
return;
function a(){}
}
// console.log("a equals to ",a); -> 1
b();
// console.log("now a equals to ", a) -> 1
so in this function i get 1 in both cases. Can somebody explain me why?
if i use const a = function() and of course put it before the return, the global variable will change to 10. Though now it does not.
My assumption is that this is not happening, because inside the function b, the variable a is a function. So the attempt a=10 will not work. But when i console.log(a) inside the b function the a is 10 and not a function.. Arghh!
Thanks in advance.
xx
so in this function i get 1 in both cases. Can somebody explain me why?
Variable a in the global scope and a inside b() belong to different scopes. Execution of b() happens in 2 phases:
Memory allocation: All variables declarations and functions in b() are first allocated memory. This is called hoisting.
This is how the global scope and local scope of b() would look like at this point: Local refers to the scope of b()
Local: {
a: function a()
}
Global: {
a: 1
}
Code execution: The line a = 10 will override and assign 10 to a inside b(). Right after this line the function returns. Note that b's execution does not modify a in the global scope. Thus, your code would log a as 1 even after b() finishes execution.
This is how the scopes would look like right before b() returns:
Local: {
a: 10
}
Global: {
a: 1
}
if i use const a = function() and of course put it before the return, the global variable will change to 10. Though now it does not.
To modify global variable a from b() you can remove function a, like this:
var a = 1;
function b() {
a = 10;
return;
}
console.log('a equals to ', a);
b();
console.log('now a equals to ', a);
Output:
a equals to 1
now a equals to 10
Why? Undeclared variables are always global in Javascript. This means that a declared in the global scope and a used inside b both reference the same variable. a=10 will therefore modify the a that was declared in the global scope.
This is how the scopes would look like:
Local: {
// no a
}
Global: {
a: 10
}
Related
Based on https://www.plivo.com/blog/Send-templatized-SMS-from-a-Google-spreadsheet-using-Plivo-SMS-API/ I have the following code:
data = {
"SOURCE" : "+1234567890",
"DESTINATION" : "+2345678901",
"FIRST_NAME" : "Jane",
"LAST_NAME" : "Doe",
"COUPON" : "DUMMY20",
"STORE" : "PLIVO",
"DISCOUNT" : "20",
}
template_data = "Hi FIRST_NAME , your coupon code for discount of % purchase at is "
function createMessage(data,template_data){
Logger.log(data);
for (var key in data) {
Logger.log(key);
if (data.hasOwnProperty(key)) {
template_data = template_data.replace(new RegExp('+key+', 'gi'), data[key]);
}
}
Logger.log(template_data);
return template_data;
}
When I run createMessage and check the logs I see:
[18-10-02 13:19:03:139 EDT] undefined
[18-10-02 13:19:03:139 EDT] undefined
This suggests to me that the parameters are not being passed into the function. What am I doing wrong?
Running a function in the Script Editor does not pass arguments to the function. Currently, you have 3 user objects in your project's global namespace (among others from Google):
createMessage (a function object)
template_data (a string)
data (an object).
The line function createMessage(data, template_data) declares the object createMessage to be a function object, and indicates that the first two arguments passed to the function are known within the function's scope as data and template_data, respectively. These function-scope argument declarations shadow any more-distant declarations (i.e. from global scope or an enclosing function scope).
The solution is then to either write a "driver function" that you actually execute, in which you define the input parameters to your called functions, or to remove the parameters from the function call:
var data = {...}; // global var
var template_data = {...}; // global var
function driver() {
createMessage(data, template_data); // uses the globally scoped `data` & `template_data` objects
var otherdata = 1,
otherTemplate = 2;
createMessage(otherdata, otherTemplate); // uses the function-scoped `otherdata` and `template_data` objects
}
function createMessage(someData, someTemplate) {
Logger.log(someData);
Logger.log(arguments[0]); // equivalent to the above line.
// ...
}
Avoiding reference shadowing:
function createMessage() { // removed `arguments` reference binding
Logger.log(data); // accesses global-scope `data` object because there is no `data` reference in the nearest scope
To help with this scenario - preventing manual execution via the Script editor of functions needing parameters - I will generally make the functions private by adding a trailing _ to the name: function cantBeRunManually_(arg1, arg2, arg3) { ... }
References:
Arguments
Private Functions
Name conflicts / shadowing
I am trying to access inputAC and inputB outside my function getVariables and I can't seem to get it working.
Here is the code I am working with but it does currently work.
func getVariables () {
var inputAC = textFieldAC.text.toInt()
var inputB = textFieldB.text.toInt()
}
var ac = inputAC
var b = inputB
Anyone have any ideas?
Thanks
You need to return the values from the function. Here is one way to do it by returning them in a tuple:
func getVariables () -> (Int?, Int?) {
var inputAC = textFieldAC.text.toInt()
var inputB = textFieldB.text.toInt()
return (inputAC, inputB)
}
var (ac, b) = getVariables()
// Since the values are optionals, you can use optional binding to
// safely unwrap the value.
if let acval = ac {
println("ac value is \(acval)")
} else {
println("alas, ac was nil")
}
These variables which are in getVariables method can not be access outside this method, because these are method local variables. Scope for accessing them is only for that method.
If you want to access them declare them as property or instance variables in class....
I would suggest you to instance this variables in class. If swift is not so different to java, you could declare them as class variables and set them in your method. Then, outside your method, you could access them with a
(this is java code, I'm sorry, but I try to give you the general idea)
In the class you should do something like this:
Int ac; int b;
In the method do something like this:
this.setInputAc(inputAc);
this.setInputB(inputAc);
Outside you should do something like this:
ac = this.getInputAc();
b = this.getInputB();
Also, declare your setter and getter for each variable
Just to give you the general idea.
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...
}
Given a function like
function printAndAdd( s: String, a: int, b: int ) {
// ...
}
Is there any way to enumerate the arguments of the function (their names as well as their types) at runtime? Something like
for ( var arg: ArgumentDescriptor in printAndAdd ) {
// arg.type yields the class object of the argument, i.e. 'String' or 'int'.
// arg.name yields the name of the argument, i.e. 's' or 'a'
}
I have a list of event handlers which have different signatures, and I get the name of the event handler to call as well as an Array of objects. I could just apply() the array to the function, but I'd like to do some error checking first to give better error messages.
You can use describeType() to find the information you seek. However for this to work the function must be public. Private methods will not be introspected by describeType().
Assuming printAndAdd is a method of MyClass, you can do this:
var metadata:XML = describeType(MyClass);
//find all the 'parameter' nodes of any method called 'printAndAdd'
var params:XMLList = metadata..method.(#name == "printAndAdd").parameter;
for each (var param:XML in params) {
var index:int = param.#index;
var type:String = param.#type;
var optional:Boolean = param.#optional == "true";
}
One thing you will not be able to find, is the name of the paramater, but I suppose its index may suffice for your goal.
If you need more powerful reflection than this, take a look at the as3commons reflect library.
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.