javascript using var keyword outside functions - global-variables

I understand what var keyword means inside functions, but now I am trying to understand what is the purpose of var keyword outside function. I made some tests (see below) and it makes no difference. So when it makes any difference if you put var keyword outside functions?
1.
example = 1;
function test(){
var example = 2;
}
test();
alert(example); //alert 1 no matter if example=1 or var example=1 before function
2.
example = 1;
function test(){
example = 2;
}
test();
alert(example); //alert 2 no matter if example=1 or var example=1 before function
3.
var example = 1;
function test(){
alert(example);
}
test(); //always alert 1, no matter if var example=1 or example=1 before function

The keyword var declares a variable in the current scope (well, technically in the same closure but lets keep it simple for now)
Since both your function (test) and your variable (example) were declared in the 'global' scope they both have access to each other meaning the function test could access the variable example
In your first example you have declared a new var called example, this means that now when you call the var example (inside the method) it will reference this variable instead.

There is a difference!
See this answer https://stackoverflow.com/a/1471738/211070, but basically:
Since variable declaration creates property with DontDelete flag, the
difference between var x = 1 and x = 1 (when executed in global scope)
is that former one - variable declaration - creates DontDelete'able
property, and latter one doesn't. As a consequence, property created
via this implicit assignment can then be deleted from the global
object, and former one - the one created via variable declaration -
can not be.

There isn't a real difference in the global space as long as you're not in strict mode.
That said, you should still use var as good programming practice. Auto-defined variables are evil.

I believe if you put a var within a function it can only be used within that function alone like a PHP IF statement where as if you put a var outwith the function then it can be used in more than one function - like a variable within that scope of the page.

The var-Keyword does exactly the same when used within functions as it does outside of them: It binds a new variable to the current scope. In the case of a function the scope is the function. Outside of a function the global scope is used. In a browser, that global scope is usually the window-Object.
lg,
flo

The var keyword declares a variable in the current scope. Without it, you are automatically declaring a new property on the window object, or accessing and modifying a same-named variable in a higher scope if one exists. In your example, there is only the global scope and the inner function scope, so var example = 1 in the global scope is, for your purposes, technically identical to just example = 1. However, if all of your above code was executed inside some other function scope, the first 2 examples would declare a global example property, whilst the third would declare a variable local to that scope.

1) The reason this alerts 1 is because even though you are invoking the test() function beforehand, it itself is invoking and creating its own closure and declaring a separate var example = 2; inside of it. (So your alert can't see it, it only sees 1). Now if you did: return example = 2; you would notice alert(example) === 2. This is because you brought the example out from the closure and it effected the previous example variable.
example = 1;
function test(){
var example = 2;
}
test();
alert(example);
2) Here, you aren't creating a new variable inside of the function, so it is able to access (through closure) the variable example outside of it, and change it to 2.
example = 1;
function test(){
example = 2;
}
test();
alert(example); //alert 2 no matter if example=1 or var example=1 before function
3) This last one is a good example of how 'closure' works here. Variables, unlike let's say the function () must be declared above something that tries to access them. Functions on the other hand don't. So although var example = 1 might be below the function test() { } itself, it doesn't matter. What's important is that it is declared before the CALL to test(). This is when the closure is created and it wraps itself around any variables etc it can see/access.
// so this ...
var example = 1;
function test(){
alert(example);
}
// and this work ...
function test(){
alert(example);
}
var example = 1; // <-- notice it's still above the test() func call, it can still see example
test(); //always alert 1, no matter if var example=1 or example=1 before function
// if var example = 1; was down here below it, it would alert "undefined", this is because
// the variable was not available within the scope when test() was called.

Related

Is console.log asynchronous?

I had an incident in my Angular 6 application the other day involving some code that looked like this:
console.log('before:', value);
this.changeValue(value);
console.log('after:', value);
changeValue() modifies value in some way. I expected to see the unmodified value in the console before the call to changeValue() then the modified value after. Instead I saw the modified value before and after.
I guess it proved that my changeValue() function worked, but it also indicated to me that console.log() is asynchronous--that is, it doesn't print out the value to the console right away; it waits for a bit... and when it finally does print the value, it's the value as it is at that moment. In other words, the first call to console.log() above waited until after the call to changeValue() before printing, and when it did, the value had already changed.
So am I correct in inferring that console.log() is asynchronous. If so, why is that? It causes a lot of confusion when debugging.
No, console.log() is synchronous. It's actually your changeValue() function that doesn't work the way you think.
First, JavaScript doesn't pass variables by reference, but by pointer to object (as do many other languages). So although the variable value inside your function and the variable value in the outer scope both hold the same object, they are still separate variables. Mutatin the object affects both variables, but direct assignments to one variable do not affect the other. For example, this obviously wouldn't work:
function changeValue(x) { x = 123; }
Second, in JavaScript the shorthand assignment a += b does not mutate the existing object stored in a. Instead it works exactly like a = a + b and assigns a new object to the variable. As mentioned above, this only affects the variable inside the function, but doesn't affect the one outside, so your changes are lost after the function returns.
More examples:
function willwork(obj) { obj.foo = "bar"; }
function willwork(obj) { obj["foo"] = 1234; }
function willwork(obj) { obj.push("foo"); }
function wontwork(obj) { obj = "foo"; }
function wontwork(obj) { obj += 123; }
function wontwork(obj) { obj = obj + 123; }

Create and define Vector

I'm looking for method to create Vector and push some values without defining variable Vector. For example:
I have function:
public function bla(data:Vector.<Object>):void { ... }
this function expects Vector as parameter. I can pass parameters this way
var newVector:Vector.<Object> = new Vector.<Object>();
newVector.push("bla1");
newVector.push("bla2");
bla(newVector);
Can I do it in one line in Flex? I'm looking for something like:
bla(new Vector.<Object>().push("bla1").push("bla2"));
I've also tried this:
bla(function():Vector.<Object> { var result:Vector.<Object> = new Vector.<Object>(2, true); result.push("bla1"); result.push("bla2"); return result; });
But it complains:
1067: Implicit coercion of a value of type Function to an unrelated type __AS3__.vec:Vector.<Object>...
Thanks
You can't chain Vector.push() calls as they return uint's -- the new vector length.
The coercion problem, on the other hand, happens because you are passing a function to the bla function, which expects a Vector.<Object>.
You could fix that easily:
bla((function():Vector.<Object> {
var result:Vector.<Object> = new Vector.<Object>(2, true);
result.push("bla1");
result.push("bla2");
return result; })()
);
However, there's already a top level function in AS3 that helps you creating vectors.
The Vector() function expects either an Array or a Vector and returns a Vector. So, for example, you could use:
bla(Vector.<Object>(['bla1', 'bla2']));
Visit the AS3 Reference for more info.
EDIT: I forgot to mention that the fix on the function approach was simply adding a () to it, meaning we actually called the anonymous function and passed it's return to the bla function.
Just want to mention push takes multiple arguments, and each one is pushed onto the stack sequentially:
function getVector():Vector.<String>
{
var newVector:Vector.<String> = new Vector.<String>();
newVector.push("blah1","blah2","blah3","blah4");
return newVector;
}
I'm not really sure why you'd need to do it one line. You could always write a wrapper class if you happen to do this often. The wrapper class could have a push method that returns a reference to the original object so you can use the first method you wanted.
You could also write a helper function which created a new vector and added the elements to the vector and then returned the vector.
Is there a particular need for wanting this on one line?
You are not able to do this:
bla(new Vector.<Object>().push("bla1").push("bla2"));
because the "push" method returns the length of the Vector. So what this means is that you are trying to push the String "bla2" onto the int 1. This won't work!
And your next example is passing a function to the bla method, not calling that function and passing the returned Vector.
Also you are saying the Vector type is "Object" but you are passing in Strings. You should do this:
Vector.<String>
You could do something like this:
function getVector():Vector.<String>
{
var newVector:Vector.<String> = new Vector.<String>();
newVector.push("bla1");
newVector.push("bla2");
return newVector;
}
bla( getVector() );

How to reference an anonymous JavaScript function?

I'm trying to call a Page Method using a jQuery 'attached' event function, in which I like to use the closure to keep the event target local, as below, but page method calls declare several 'error' functions, and I would like to use one function for all of them. If, in the below code, I was handling an error and not success, how could I use my single, anonymous handler for all 3 error functions?
$(":button").click(function () {
var button = this;
PageMethods.DoIt(
function (a, b, c) {
alert(button);
});
});
This example passes an anonymous function for the success callback. There is only one of these. If I was passing an error callback, how could I use 'function (e, c, t)' for all 3 error callbacks?
ADDED: What I would like to do here is trigger an AJAX call whenever the user clicks a toggle button (checkbox), but to improve responsiveness, I want to toggle the button state immediately, and only 'untoggle' it if the AJAX call fails.
Now, in my client-side click() event handler, I would like to use anonymous functions inside the scope of click()' so that the functions have access to thethisevent argument, but I don't want to 'declare' three functions for theonTimeout,onError, and 'onAbort arguments of the PageMethods.MyFunction function. if I declare a named function outside of the click handler, it no longer has access to the 'this' parameter of the click() event handler.
If your goal is to keep this function out of global scope, use the module pattern:
(function() {
function asplode() {
alert('Your head asplode.');
}
$('body').click(asplode);
})();
I think you can put a variable with name in front of it, like this:
var myFunction = function(a, b, c) { ...
It's been a while I haven't done this but you could give it a try.
You have to assign an anonymous function to a variable using var (always use var, otherwise a variable gets global scope, which may cause unexpected results (e.g., never declare variable i globally)). That's the only way to reference it:
var myFunction = function (a, b, c) {
/* tum de dum */
}; // don't forget this semicolon
Then you can use this function in different places:
$(":button").click(myFunction);
/* don't put braces after the function name when referencing it,
else it will be called immediately */
You can find more information about function expressions and function declarations in the article Named function expressions demystified.
You can't. The whole point of an anonymous function is that it has no name and thus cannot be referenced. (In fact, "anonymous" is basically the Greek word for "unnamed".)
If you want to reference it, you need to give it a name.
From inside the anonymous function, you can reference it as arguments.callee (this is how anonymous recursion is achieved).
If I understand correctly what you want to do, you may be able to accomplish it like this:
function handler(a, b, c) {
alert(this); // button
}
$(":button").click(function () {
var button = this;
PageMethods.DoIt(function () {
handler.call(button, a, b, c);
});
});

Passing optional arguments (...rest) through to another method that takes optional arguments in AS3

I have a "format" method that works in a similar manner to the C# String.Format method, with the following signature:
In a class named StringTools:
/**
* Formats a string, based on C# String.Format method.
* #param raw A string with numbered tokens, such as "{0}, {1}"
* #param rest Values that replace the numbered tokens in raw.
*/
public static function format(raw:String, ...rest:*):String;
StringTools.format("{0}, {1}", "Hello", "World") returns the string "Hello, World" as expected. Now, I'm trying to get my logging class to use this method, but I'm having trouble passing the optional variables through. The signature of the method in the logging class is:
public static function infof(raw:String, ...rest:*):String;
If I pass "rest" directly into StringTools.format(raw, rest), it's passed in as an array, and not as a series of parameters, so if I call it liks this: infof("{0}, {1}", "Hello", "World"), I get the string "Hello,World, {1}", since it replaces the first token with the entire array of values.
I also tried constructing an arguments array, and calling the method like this:
var collectArgs:Array = [raw];
for (var i:Number = 0; i < rest.length; i++)
{
collectArgs.push(rest[i]);
}
var callFunction:Function = StringTools.format.call;
trace(callFunction.apply(null, collectArgs));
However, this traces "World,6". So, it looks like the parameters are shifted. So, I tried initializing collectArgs as [null, raw], and I get "Hello World,6. The number is {1}" again.
Am I doing something wrong? What is the correct way to pass optional parameters from one method that expects optional parameters to another method that expects optional parameters?
Thanks!
I think you are on the right lines using apply. This seems to do illustrate the behaviour you want:
static function f1(raw:String, ...rest:*):void
{
trace("f1: "+raw+" "+rest);
rest.unshift(raw);
f2.apply(null, rest);
}
static function f2(raw:String, ...rest:*):void
{
trace("f2: "+raw+" "+rest);
}
function passSomeArguments():void
{
f1("A",1,2,3);
}
EDIT: You need to pass 'null' as the 1st parameter to apply because the first parameter is what is considered to be 'this' when the function is called. Since the functions are static (and in any case have no dependency on 'this') you can pass null, but you must pass something.
You could also do something like this (of course this is not best implementation for the string formatting):
public static function format(raw:String, ...rest:*):String {
if (rest[0] is Array && rest.length == 1) {
rest = rest[0];
}
var r:RegExp = /(\{\d+\})/g;
var matches:Array = raw.match(r);
for (var i:Number = 0; i < rest.length; i++) {
raw = raw.replace(matches[i], rest[i]);
}
return raw;
}
Then your infof function would just look like this:
public static function infof(raw:String, ...rest:*):void {
var formatted = StringTools.format(raw, rest);
}
As mentioned in my comment, if you remove the call method from the end of you callFunction setter, then you do not need to supply null as the first argument. See http://livedocs.adobe.com/ to understand what the call method actually does, and what the first parameter is for.
As #stephen mentioned, it is a lot simpler to unshift your raw var onto the rest array, rather than building up a new one.
Actually, just found that it's my problem. It should work fine using the argument collection method described, as long as the first element in the arguments array is null. I'm not sure why null is necessary, but it works fine this way.

Passing in variables ByRef in Actionscript 3

Is it possible to pass a parameter to a method ByRef (or out etc) in ActionScript 3?
I have some globally scoped variables at the top of my class and my method will populate that variable if it's == null.
I'm passing in the variable which needs to be populated but so far my efforts have returned a locally populated variable leaving the globally scoped version of it still null.
The variable being passed to my method varies so I can't hardcode it in my method and simply set it.
ActionScript 3 passes params by reference by default, like Java - except for primitive types. But what you are trying to have it do isn't passing by reference. The parameter passed in is a reference to an object(in the case when it's not a primitive type), which you may well modify inside of the function.
But, to answer your question. Here is a solution:
function populateIfNull(variableName, value){
this[variableName] = this[variableName] || value
}
Which you can use like:
populateIfNull('name', 'Bob')
populateIfNull('age', 20)
AS3 does not have pass by reference (it is similar to Java in this regard, in that it passes references by value).
Something similar can be simulated if you control the client code by wrapping the object in another object:
var myObj = null;
myFun({ a: myObj });
function (param) {
if (param.a == null) {
param.a = "Hello";
}
}
Use objects.
eg:
var myObj : Object = new Object();
var myArr : Array;
myObj.arr = myArr;
function populateViaRef(obj : Object) : void {
obj.arr = new Array();
for(var i : Number = 0; i < 10; i++)
obj.arr[i] = i;
}
populateViaRef(myObj);
for(var i : Number = 0; i < 10; i++)
trace(myObj.arr[i]);
In ActionScript 3.0, all arguments are passed by reference, because all values are stored as objects. However, objects that belong to the primitive data types, which includes Boolean, Number, int, uint, and String, have special operators that make them behave as if they were passed by value.
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f56.html
In Java arguments are passed by value.
http://javadude.com/articles/passbyvalue.htm

Resources