I have a JavaScript function named showchild(pgid). I have called function on document ready...
$(document).ready(function()
{
var pgid = $('#hiddenuserkey').val();
//alert(pgid);
showchild(pgid);
setInterval("showchild(pgid)",1000);
});
You are using it in the worst possible way - passing a string.
Use the following code instead:
setInterval(function() {
showchild(pgid);
}, 1000);
When passing a string, it will be evaluated in the global context without having access to any non-global variables. By passing a function (the preferred way) all accessible variables are preserved in the function's closure so pgid is defined inside that function when it's called.
Related
Hi I have the following closure
function createCounter() {
var numberOfCalls = 0;
return function() {
return ++numberOfCalls;
}
}
var fn = createCounter();
fn()
fn()
And I believe I understand about scope and the fact that the inner function keep the outer function's values after the outer one has returned.
What I don't understand is why I need to create this variable
var fn = createCounter()
and then invoke the variable fn() instead of initially invoking createCounter()
I saw that createCounter() just returns 'function()' instead of what has to be '1' and I don't understand why.
Thanks for the help. Read many tutorials still having problems with understanding this.
Please note: the question's isn't about how to make the code more eloquent or better, it's about understanding of what's been done
When createCounter is called it returns another function and that returned function is not evaluated unless you do so. Remember, in JavaScript functions are objects too. They can be the return value of a function.
So when you do this:
var fn = createCounter();
fn references only the function returned by createCounterfunction and not its evaluated value.
If you need to evaluate the function returned by createCounter try something like:
createCounter()();
This evaluates the returned function.
If you call it like this it will always return the same value as it creates a new numberOfCalls variable every time you call createCounter.
In Javascript, functions are objects which can be passed to and returned by other functions, as any other objects (e.g. a string, a number...).
So doing:
function foo(arg) { /* ... */ }
var someObject = new String("Hello");
foo(someObject);
is similar as:
function foo(arg) { /* ... */ }
var someFunction = new Function("Hello", "...");
foo(someFunction);
A function may thus return another function, which can be invoked as needed.
function foo() {
return new Function(...);
}
var functionReturnedByCallingFoo = foo();
functionReturnedByCallingFoo(); // can be invoked
functionReturnedByCallingFoo(); // and again
functionReturnedByCallingFoo(); // and again
Now, functions are almost never declared using the Function constructor, but rather with constructs named "function declarations" or "function expressions" - basically, the way we have defined the function "foo" in the previous examples, with a function signature and a function body delimited by curly brackets.
In such cases, the statements inside of the function body can read and write variables declared outside of the function itself ("free variables"), and not only variables declared within the function, as per the rules of lexical scoping. This is what we call a closure.
So in your case, the createCounter() function, when invoked, defines a local variable named "numberOfCalls", then return a function - the body of which having access to that variable. Executing the returned function changes the value of the variable, at each invocation, as it would for any "global" variable (i.e. variables declared in outer scopes).
Executing the createCounter() function many times would simply, each time, recreate a new local variable "numberOfCalls", initialize it to zero, and return a new function object having access to that variable.
Got a problem, don't know how can I give to ClickSimClick function arguments exposed by ClickSimMove func (it returns array with 2 values).
Code below says that crd is undefined on setTimeout.
var crd = plugin().ClickSimMove();
setTimeout("plugin().ClickSimClick(crd[0], crd[1])", 1000);
Pass a function, not a string:
var crd = plugin().ClickSimMove();
setTimeout(function() {
plugin().ClickSimClick(crd[0], crd[1]);
}, 1000);
When you pass a string, it's evaluated as it would be with eval in the global scope, losing all access to local variables. An anonymous function lets you reference any variable in scope.
var crd = plugin().ClickSimMove();
setTimeout(function(){
plugin().ClickSimClick(crd[0], crd[1]);
}, 1e3);
When at all possible, avoid sending strings to setTimeout/setInterval--use an anonymous function instead. Especially if you find yourself concatenating variables to make that string, you can run in to trouble very quickly with some sort of injection or malformed component.
I recently learned javascript. I was experimenting with it. Now, I tried to make a simple timer. Here is the code:
<html>
<head>
<script type="text/javascript">
function start(obj)
{
var t = setTimeout("increment(obj)", 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
</script>
</head>
<body>
<p onclick="start(this)">0</p>
</body>
</html>
The contents of the <p></p> should be incremented by 1 every second. Does anyone know why this doesn't work?
Because the string you pass into setTimeout is evaluated at global scope, not the scope within the function, and so doesn't refer to your obj object.
You should never pass strings to setTimeout. Instead, pass it a function reference:
function start(obj)
{
var t = setTimeout(function() {
increment(obj);
}, 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
The function we're passing to setTimeout is a closure, which means it has an enduring reference to the items in scope where it's defined. So a second later when the timer mechanism calls it, it still has access to the obj argument of your start function even though the start function has long since returned. More here: Closures are not complicated
The issue (or at least, the first that I see) is that you are passing the string "increment(obj)" to the setTimeout() method, but obj is only defined inside of your start() method. The string that you pass isn't actually evaluated until the timeout triggers, at which point no obj variable is in scope.
There are a few different ways around this. One is to pass a closure to setTimeout() instead of a JavaScript string, like:
function start(obj) {
var nextIncrement = function() {
increment(obj);
};
var t = setTimeout(nextIncrement, 1000);
}
Another (though less preferable) option is to promote obj to the global scope, like:
function start(obj) {
window.obj = obj;
var t = setTimeout("increment(obj)", 1000);
}
In general, however, you should avoid passing a string to setTimeout (and you should also avoid placing things in the global scope unnecessarily). As you have seen, it can cause issues with scope resolution, and for any non-trivial operation it also makes you code much less maintainable. Always prefer passing a function closure when possible.
Also, the following line of code is probably not doing exactly what you expect:
parseInt(obj.innerHTML)
You should always provide the radix argument to parseInt, to avoid errors with values such as 011 (which is 9, rather than 11, because it is evaluated in base-8 due to the leading 0). You can avoid these quirks by simply doing:
parseInt(obj.innerHTML, 10)
...to force a base-10 parse.
Anyways, working example here: http://jsfiddle.net/dSLZG/1
The problem is with this line of code:
var t = setTimeout("increment(obj)", 1000);
obj is an identifier in the functions scope -- it is only accessible within the start function. When you pass a string to setTimeout, it is evaluated in the global scope. This means that the obj variable is not available, so nothing is incremented.
You should pass a function object instead, as this will create a closure and your variable will be accessible:
function start(obj)
{
setTimeout(function() {
increment(obj);
}, 1000);
}
Note that I have removed the unnecessary var t =, because you're not doing anything with the timer identifier.
I've copied your code over to jsFidle and added a working example. See sample code.
The problem in your original version is that your variable obj is not defined in the global context. Whenever you pass strings to setTimeout you'll end up having the string evaluated in the global context (where obj is not a variable).
What you should do instead is never pass a string to setTimeout but a function object. This function object holds references to all variables that are set where the function object was defined.
So, because the function object passed to setTimeout in start2 is defined within start2 it has access to all variables and parameters of start2. Your variable obj is one of those and thus accessible within the function object as soon as it is executed by setTimeout.
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.
Why does calling my JavaScript function throw an error when I call it like this
wysiwyg2();
var wysiwyg2 = function()
{
alert(1);
}
but work when I do this?
wysiwyg2();
function wysiwyg2 ()
{
alert(1);
}
You need to define your function variable first, i.e.
var wysiwyg2 = function()
{
alert(1);
}
wysiwyg2();
For a good explanation of the difference, see Why can I use a function before it’s defined in Javascript?
In the first snippet, you're trying to invoke a variable before the variable is defined.
You'd get the same problem from the following code:
test.toString();
var test = new Date;
In the second snippet, you're declaring the function without assigning it to a variable, and this results in a global declaration that is usable in earlier code.
You can think of your javascript as though it's evaluated in two passes. The first pass builds all the objects and names (and remember: functions are objects), and places them "in scope", so to speak. It's kind of like a compilation step. Then the second pass executes the code.
So your second sample works because the first pass built and "scoped" the function before execution. The first sample does not work because the function object is created as part of a variable assignment, and so it's not in scope yet when you try to call it.
You mention another situation in the comments, where the function call and definition are separated into two script blocks. That doesn't work because the engine completes both steps of one block before moving on to the next, and you tried to call the function in a block that is executed before the block where it's defined. You can call function across script blocks, but not until they are defined.
In the first one, you're declaring a function and assigning it to a variable. Thus you won't be able to call it through that variable until it's actually assigned to it.
In the second, you're declaring a named function. And can call that function from wherever (as long as it's in scope).
When entering a new execution context (which is either a function call or global code), JavaScript first goes through a variable instantiation phase during which all variable declarations and function declarations within the global code or function body are examined and create as properties of the current variable object, which is effectively a collection of all the objects that are in the current scope. In particular, any function declaration such as
function wysiwyg2 ()
{
alert(1);
}
... is fully created during this phase, while any variable declaration such as
var a = 2;
... only leads to the creation of a variable called a with a value of undefined during this phase. This is also true of a variable declaration with an assignment to a function expression, such as
var wysiwyg2 = function()
{
alert(1);
}
Only the variable instantiation takes place at this point. Once this phase is complete the rest of the code (including variable assignment) is executed sequentially.