Solved

Variable passing in anonymous functions

Posted on 2014-03-07
9
351 Views
Last Modified: 2014-03-21
I'm a bit confused..

It is possible to do:

function setVariable(func) {
        func['variable'] = 'foobar';
}

function a () {
        setVariable(this);
        console.log(this.variable);   // "foobar"
}

Open in new window


------

But not this?


var initFunctions=[function()  {
        console.log(this.variable);   // "undefined"  
}];

for(x = 0; x < initFunctions.length; x++) {
        initFunctions[x]["variable"] = "foobar";
        initFunctions[x]();  // Run function
}




// Why da fork does the second one become undefined?
// What do I miss? I know I can return the variable value as an argument instead like:

var initFunctions=[function(returnedValue)  {
        console.log(returnedValue);   // "foobar"  
}];

for(x = 0; x < initFunctions.length; x++) {
        initFunctions[x]("foobar");  // Run function
}

Open in new window


But that's not as neat as declaring variables on the run...
help?....
0
Comment
Question by:walkman69
  • 5
  • 4
9 Comments
 
LVL 2

Author Comment

by:walkman69
ID: 39914228
um.. Its since it hasn't become an own instance yet?.. right?
Then this is impossible to do for anonymous functions?
0
 
LVL 42

Accepted Solution

by:
Rob Jurd, EE MVE earned 500 total points
ID: 39915710
This is a scope issue.  You don't have access to the functions private assets in the 2nd set of code but you do in the first and third because javascript passes by reference.
function setVariable(func) {
        func['variable'] = 'foobar';
}

function a () {
        setVariable(this);
        console.log(this.variable);   // "foobar"
}

Open in new window

Is essentially
function a() {
    this.variable = "foobar";
    console.log(this.variable);
}

Open in new window

So you have access to the private memebers because you are creating them within the function.

In your 2nd lot of code above you are trying to essentially set a private variable external to the function
Eg
initFunctions[x] is the function so initFunctions[x].variable isn't the same as first passing the value to the function and the function setting it from within.
Consider this variation to your code for the 2nd set that was giving you undefined:
http://jsbin.com/ziyoz/1/edit
var initFunctions=[function()  {
        this.variable = "foobar2a";
        console.log(this.variable);  
}];

for(x = 0; x < initFunctions.length; x++) {
       initFunctions[x].variable = "foobar2"; 
       console.log(initFunctions[x].variable);
       initFunctions[x](); // run the function
}

Open in new window

0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 39915721
Remember that all javascript elements are objects and some more simple than others.  A function is just a basic class with itself as the constructor.
Some extensions on the basic function when you think of it as an object rather than a standalone function:
http://jsbin.com/loves/1/edit
var func = function a(myname) {
    this.name = myname;
    var name2 = myname + "_more";

    function b() {
        console.log("B");
    }
    this.c = function() {
        console.log("C");
        b();
    };
    this.getName = function(){
        console.log(this.name);
    };
    this.getName2 = function() {
        console.log(name2);
    };
    this.getStatic = function(varName) {
        console.log(func[varName]);
    };
};

// create an instance of the class so internal members are accessible
var myvar = new func("rob");
myvar.getName();              // "rob"
myvar.name = "not rob";
myvar.getName();              // "not rob" as name is public
console.log(myvar.name2);     // "undefined" as name2 is private
myvar.getName2();             // "rob_more"
//myvar.b();                  // throws an error and halts execution! as b() is private
myvar.c();                    // "C" AND "B" as can access the private function b()

func.variable = "rob2";
console.log(func.variable);   // "rob2" as it is statically set on the object
console.log(myvar.variable);  // "undefined" to show the instance cannot access a static member externally
console.log(myvar.getStatic("variable")); // "undefined" to show that the instance cannot access the object variable from inside the object.  This would make no sense as the class would never know about the external assignment

Open in new window

0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 39922482
Did what I post make sense?  If not, ask away as it's not the easiest of topics to get your head around.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 2

Author Comment

by:walkman69
ID: 39928351
I'm sorry for not responding earlier. I didn't think someone would respond to the question..
It makes perfect sense.. I know about private/public scope in Javascript. There were some uncertainties that I had in my knowledge of the inner workings of javascript.. I think you cleared the last piece of the puzzle..

If I explain my whole situation, it's for a piece of code launched after an ajax-call.

After posting here I wrote it to look something like this:
Note that because I have a similair piece of code written in 10 000 rows of code here and there (but Without the declaration of the anonymous function directly IN callAjax arguments.. But as separate instantiated global functions.) I had to add some code to the ending of the argument list, so that I don't need to rewrite 10 000 rows of code..
I will do however.. but not right now.. I'm in a bit of a hurry.. ;)

Anyways It looks somewhat like this now:


var someOutsideVariable = "The GNU Is an almighty and powerful creature..";

var params = 'url=' + '../somedirectory/foo.bar' + '&data=' + data + '&id=' + g.user_id + '&ver_str=' + g.user_ver_str; // The last parameters is only to make sure the right user loads the file and noone else.
                                                
callAjax(
      method='POST',
       url=g.urlroot + g.extraSubDir + '/login/php_includes/proxy_put_file.php',
       params=params,
      async=true,
       getResponse=true,  // This posts the responseText in namespace g.responseText
      namespace=g,
       initFunctions=[function(responseText, args){
            
            // And here goes the code..
            console.log(args.someOutsideVariable);   // Story about GNU appears..
            console.log(responseText);   // Shows responseText
            
}], elem='', errorReport=false, args={
      'someOutsideVariable' : someOutsideVariable,
       'eventualOtherVariable' : eventuallyOtherVariable;
}
);            
                                                

When the callAjax-function has loaded the file, it falls back to calling
initFunctions like this:

function initFunctionsLoader(responseText, args) {      
       if (initFunctions.length > 0) {
             for(x = 0; x < initFunctions.length; x++) {
                   initFunctions[x](responseText, args);
             }
       }
}



I had to renew atleast a piece of the code since it's storage of responseText in
g.responseText is unresponsibe since it can easily be overwritten by a simultaneus callAjax() and then the result is something totally different.  But up until now, I only used callAjax() with .async = false; Don't even ask me why.. I've been under a lot of stress.. But so far it worked.. Now I want to start making more use of asynchronization and that's why I needed both passing of functions as well as arguments. And I find coding with anonymous functions more appealing than instantiations.. But I don't really like having to send the arguments each time with the "args"-argument list. This quickly gets booring when nestling the init-functions with another callAjax()-call with more initFunctions.. That is.. If I need for example the same variable in every function.
Ok, you may probably suggest the passing around a common namespace or something here.. And perhaps that's one way to go.. I'm just curious what way would be the best..

I liked your explanations..
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 39928374
*laughing* I read your previous comment saying to myself "he really should use a namespace here to prevent variables from being accidently overriden"... !  So that should answer your question.

If it's not your variable then you have to be careful as javascript does everything by reference

take the following code:
var a = {};
var b = a;

a.name = "a";
a.value1 = 10;
b.name = "b";

console.log(a);  // [Object] name: "b", value1: 10
console.log(b); // [Object] name: "b", value1: 10

Open in new window


Both objects will spit out the same values to the console. see the comments in the code above.
To get around this you need to copy the object, value by value.

I mentioned this because you set g=namespace and if g.user_ver_str is not your namespace, (could be google's?) then any changes you make to g will be reflected in namespace and vice versa.

I've written an article on this as it spurred my interest :)
http:A_13138-Javascript-is-just-an-Object.html

It sounds to me though that you're on the right track with all of this.  Anything in particular you'd like me to clarify?
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 39933119
Did my last post answer your questions? Did the article help?
Happy to continue the discussion :-)
0
 
LVL 2

Author Comment

by:walkman69
ID: 39945888
Oh.. nice.. I'm happy I can spurr you..
I read it.. sweet article =)

yea.. g is my namespace.. don't wear it out ;)
Funny story though ^^

I think i'm all good for now..
My understanding has increased somewhat. And i'm more sure
that the path i'm about to embarc uppon is perhaps more accurate
in terms of javascript "perfection".. than it has been earlier..

Of course one could ask if asynchronous mode is always the best option.
And most people would probably say that it is.. However I think that
there are moments where no other activity is running where one can take the time
to run something and expect a result back without delay..

But I think i'll stick to async for a while now and throw in some of thoose
peachy namespaces.. It will be awesum.. ;)

Thanks Rob!

// Walkman69
0
 
LVL 2

Author Closing Comment

by:walkman69
ID: 39945905
Your help was deeply appreciated and your comments were exeptionally thorough.. thanx!
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Today I would like to talk about localizing (Internationalization) JavaScript applications. Introduction When creating an application that is going to be used by many people around the globe, it is important to remember that not everyone speak…
Introduction HTML checkboxes provide the perfect way for a web developer to receive client input when the client's options might be none, one or many.  But the PHP code for processing the checkboxes can be confusing at first.  What if a checkbox is…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now