Accessing a variable inside a method's function in JavaScript - javascript

I'm a novice at JavaScript so please forgive any incorrect terminology/understanding.
I'm trying to extract a variable thebest from a callback function function(thebest,all) within a method ec.get.
I've done a little reading up on scope and I was expecting the code below to work, but it appears the thebest variable outside the function is in a different scope than the variable inside the method's function.
var thebest = 0;
ec.get("id", function(thebest,all) { });
alert(thebest);
I have also tried using a different variable name on the outside but it made no difference. How can I access the value of the "innermost" thebest variable from outside the method and its function? Thanks!

It looks like there are several issues here:
Issue 1: If you want to change the value of theBest in the callback function, you can't change it by passing it as a parameter. Simple variables are passed by value so the original isn't changed if you change it in the function.
Issue 2: Assuming ec.get() is a networking operation, it's probably asynchronous which means that the callback function you pass it isn't called until much later. That means, the completion callback function will not have executed yet when your alert fires. So, it won't have changed anything yet.
Issue 3: You can't pass arguments to a callback the way you have it declared. That will define those arguments, but unless ec.get() is going to pass arguments just like that, the arguments won't actually be there when it's called. Remember, it's ec.get() that calls your function internally. It alone decides what arguments your callback gets. You can't change that.
Issue 4: When you declare an argument for your function with the same name as a local or global variable (thebest in your example), you create a name conflict which causes the argument to take over that name for the scope of your function and make the higher level variable inaccessible. In general, it's a bad idea to name a function argument with the same name as any other variable that is in scope. It just asks for you or other people reading your code to get confused and make wrong assumptions about what is getting modified or read when using that name.
One way to do this is as follows:
var thebest = 0;
var all = "whatever";
ec.get("id", function() {
// use the arguments "thebest" and "all" here which are available
// from the higher scope. They don't need to be passed in
alert(thebest);
alert(all);
});
// you can't alert on the value of thebest and all here because
// an asychronous callback won't have yet been called and
// won't have yet modified those values

If the callback is something that executes promptly (not async) then you can simply assign it out to a differently named variable. For example
var theBest = 0;
ec.get("id", function(theBestArg,all) { theBest = theBestArg; });
alert(thebest);

Your problem is that you are redeclaring theBest as an argument for your function.
var thebest = 0;
ec.get("id", function(theNewBest,all) { theBest = 'new value' });
alert(thebest);

Related

When will an anonymous function be used?

For example below is an anonymous function that has been placed in parentheses so now the function can be stored as a variable and called on else where as seen in number 2, However how can script number 1 be called to run? How can it be identified if it has no name? And how to change an anonymous function to a defined function?
**Number 1**
(function() {
// Do something
})();
**Number 2**
(var funcName = function() {
// Do something
})();
funcName();
The first function is called immediately because it is followed by () which calls a function.
Then if you were to remove the () from around the var statement (which is an error):
The second function is also called immediately, for the same reason.
The value stored in funcName (which is called as if it were a function, so will cause an error if it is not a function) is the return value of the second function (and is defined by the code you represented as // Do something — the "something" needs to include "return a function").
How can it be identified if it has no name?
Names are only really useful for use in debuggers (where they are very useful in stack traces and the like). For identifying a function to call, you access them like any other object or primitive (via a variable, property, etc). A function declaration just creates a variable with a matching name in the current scope.
Yes, these are anonymous functions, but they are also functions that are being called / invoked immediately, and hence don't need names to be referred to later.
There are many uses for Immediately-Invoked Function Expression (IIFE), but one is to use functions to establish namespaces that do not pollute global

Using Variables as Parameter Names

Let's say I want to make a JavaScript function which sets variables to numbers, using the following format. It would not work, but why exactly? How could it be made to work?
function variableSet(varName, varValue) {
varName = varValue;
}
The idea is to create a variable with the name used as a parameter, and give it the value of the second parameter. How could this be done?
Not sure I understand your question. But if you need to give a variable name and it's value to overwrite the variable, it can be done like that:
this[varName]=varValue;
In this case "this" is your context, in which variable was defined. If you need to provide the other context, you can put it as other parameter, so function will look like this:
function variableSet(varName, varValue, context) {
context[varName]=varValue;

Clarification of JavaScript variable scope

I already know how to make this code work, but my question is more about why does it work like this, as well as am I doing stuff right.
The simplest example I can make to showcase my issue is this :
Lets say I have a function that increments the value of an input field by 10 on the press of a button.
var scopeTest = {
parseValue : function( element, value ) {
value = parseInt( element.val(), 10 );
//Why does this not return the value?
return value;
},
incrementValue : function( element, button, value ) {
button.on('mousedown', function (e) {
//Execute the parseValue function and get the value
scopeTest.parseValue( element, value );
//Use the parsed value
element.val( value + 10 );
e.preventDefault();
});
},
init : function () {
var element = $('#test-input'),
button = $('#test-button'),
value = '';
this.incrementValue( element, button, value );
}
};
scopeTest.init();
The above code doesnt work because the parseValue method doesn't properly return the value var when executed inside the incrementValue method.
To solve it apparently I have to set the scopeTest.parseValue( element, value ); parameter to the value variable like this:
value = scopeTest.parseValue( element, value );
Than the code works.
But my question is why? Why is this extra variable assignment step necessary, why the return statement is not enough? Also I am doing everything right with my functions/methods, or is this just the way JavaScript works?
Working example here => http://jsfiddle.net/Husar/zfh9Q/11/
Because the value parameter to parseValue is just a reference. Yes, you can change the object, because you have a reference, but if you assign to the reference it now points at a different object.
The original version is unchanged. Yes, the return was "enough", but you saved the new object in a variable with a lifetime that ended at the next line of code.
People say that JavaScript passes objects by reference, but taking this too literally can be confusing. All object handles in JavaScript are references. This reference is not itself passed by reference, that is, you don't get a double-indirect pointer. So, you can change the object itself through a formal parameter but you cannot change the call site's reference itself.
This is mostly a scope issue. The pass-by-* issue is strange to discuss because the sender variable and the called functions variable have the same name. I'll try anyway.
A variable has a scope in which it is visible. You can see it as a place to store something in. This scope is defined by the location of your function. Meaning where it is in your source code (in the global scope or inside a function scope). It is defined when you write the source code not how you call functions afterwards.
Scopes can nest. In your example there are four scopes. The global scope and each function has a scope. The scopes of your functions all have the global scope as a parent scope. Parent scope means that whenever you try to access a name/variable it is searched first in the function scope and if it isn't found the search proceeds to the parent scope until the name/variable is found or the global scope has been reached (in that case you get an error that it can't be found).
It is allowed to define the same name multiple times. I think that is the source of your confusion. The name "value" for your eyes is always the same but it exists three times in your script. Each function has defined it: parseValue and incrementValue as parameter and init as local var. This effect is called shadowing. It means that all variables with name 'value' are always there but if you lookup the name one is found earlier thus making the other invisible/shadowed.
In this case "value" is treated similar in all three functions because the scope of a local var and a parameter is the same. It means that as soon as you enter one of the methods you enter the function scope. By entering the scope the name "value" is added to the scope chain and will be found first while executing the function. And the opposite is true. If the function scope is left the "value" is removed from the scope chain and gets invisible and discarded.
It is very confusing here because you call a function that takes a parameter "value" with something that has the name "value" and still they mean different things. Being different there is a need to pass the value from one "value" to the other. What happens is that the value of the outer "value" is copied to the inner "value". That what is meant with pass-by-value. The value being copied can be a reference to an object which is what most people make believe it is pass-by-reference. I'm sorry if that sounds confusing but there is too much value naming in here.
The value is copied from the outer function to the called function and lives therefor only inside the called function. If the function ends every change you did to it will be discarded. The only possibility is the return your "side effect". It means your work will be copied back to a variable shortly before the function gets discarded
To other alternative is indeed leaving of parameters and work with the scope chain, e.g. the global scope. But I strongly advize you not to do that. It seems to be easy to use but it produces a lot of subtle errors which will make your life much harder. The best thing to do is to make sure variables have the most narrow scope (where they are used) and pass the values per function parameters and return values.
This isn't a scoping issue, it's a confusion between pass-by-reference and pass-by-value.
In JavaScript, all numbers are passed by value, meaning this:
var value = 10;
scopeTest.parseValue( element, value );
// value still == 10
Objects, and arrays are passed by reference, meaning:
function foo( obj ){
obj.val = 20;
}
var value = { val: 10 }
foo( value );
// value.val == 20;
As others have said it's a pass-by-ref vs pass-by-val.
Given: function foo (){return 3+10;} foo();
What happens? The operation is performed, but you're not setting that value anywhere.
Whereas: result = foo();
The operation performs but you've stored that value for future use.
It is slightly a matter of scope
var param = 0;
function foo( param ) {
param = 1;
}
foo(param);
console.log(param); // still retains value of 0
Why?
There is a param that is global, but inside the function the name of the argument is called param, so the function isn't going to use the global. Instead param only applies the local instance (this.param). Which, is completely different if you did this:
var param = 0;
function foo() { // notice no variable
param = 1; // references global
}
foo(param);
console.log(param); // new value of 1
Here there is no local variable called param, so it uses the global.
You may have a look at it.
http://snook.ca/archives/javascript/javascript_pass

Javascript - passing value to a callback

I have this JS code. I need to pass the loadItemUrl value to the callback function off loadStruct method. The loadStruct is a function of a JS framework that we're using.
In this example is the loadItemUrl value undefined in the inner scope of the callback function.
Form.prototype.Create = function (loadItemUrl) {
var dhxForm = new dhtmlXForm(this.divId);
dhxForm.loadStruct(this.url, function () {
if (loadItemUrl)
this.load(loadItemUrl);
});
}
If loadItemUrl is undefined then it is because you aren't passing a defined value to Form.Create when you call it.
The callback function is defined in the scope of the Create function, so it will have access to any variables that exist there.
In this example is the loadItemUrl value undefined in the inner scope of the callback function.
I'm assuming that's your question, in which case the answer is no. The loadItemUrl argument is scoped as a local variable to the outer function block and is therefore accessible from the inner function block.
The code you have should work fine, assuming the loadItemUrl argument is correctly passed to the Form.prototype.Create function.
The parameter loadItemUrl will be accessible to the callback function, which will, in this case, form a closure. However, in the execution context of the anonymous callback function, the value of this is entirely determined by the implementation of loadStruct. One way to solve it is to take further advantage of the closure capabilities of JS and do
var dhxForm = new dhtmlXForm(this.divId);
var self = this;
dhxForm.loadStruct(this.url, function () {
if (loadItemUrl)
self.load(loadItemUrl);
});
That would make sure that load is invoked on the correct object.

Advanced parameter usage

//This is the function that will run every time a new item is added or the
//list is sorted.
var showNewOrder = function() {
//This function means we get serialize() to tell us the text of each
//element, instead of its ID, which is the default return.
var serializeFunction = function(el) { return el.get('text'); };
//We pass our custom function to serialize();
var orderTxt = sort.serialize(serializeFunction);
//And then we add that text to our page so everyone can see it.
$('data').set('text', orderTxt.join(' '));
};
full code is at http://demos.mootools.net/Dynamic.Sortables
var serializeFunction = function(*el*) { return el.get('text'); };
var orderTxt = sort.serialize(serializeFunction*(el)*);
compare the codes.
Is el being passed or not? what is going on???
I want to learn advanced parameter usage.
If not declaring functions like function name(parameter1, parameter2, parameter3...).
If not calling functions like name(parameter1, parameter2, parameter3...).
If parameters aren't variables.
If declaring functions like function(parameter1, parameter2, parameter3...).
If calling functions like variable(parameter1, parameter2, parameter3...).
If parameters are objects.
I'm interested.
You probably have a bookmark with the lessons in which I'm interested... please, share!!!
The value assigned to "serializeFunction" is actually an anonymous function, you can see it like a pointer or reference to a function, "el" is simply a declared input parameter that will be used then that function will be called.
Looking at the original code of the one that was posted, the call of the sort.serialize function, receives only the function as a parameter, the "serializeFunction" is not being invocated, it's only passed as an argument.
So, the serialize function that receives the reference of the function passed as a parameter it will be in charge of execute it internally.
This is a lambda expression like.
sort.serialize()
accept the function as parameter, not the value.
The first code is probably correct.
In JavaScript, functions are stored in variables just as any other value (as you see with serializeFunction), and sort.serialize only takes a reference to serializeFunction. Then serializeFunction is called from sort.serialize with the current element (el).
The second code would send an undefined value to the serializeFunction (since el has not been defined in that scope) which would throw an error. Even if el was defined, sort.serialize expects a reference to a function, not a value.

Categories

Resources