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.
Related
I was going over closures and usually I look at a closure as a function that has been returned from another function or is a function that is set to a global while inside another function so that the new function (returned function or global variable) has a reference to the variables inside the initial enclosing function where it was created. Recently, someone told me that the map or reduce function form closures. These return a value or values and no function whatsoever. I dont see how this method forms a closure when all you have is a callback. In fact, MDN states that the reduce function returns a "value" and the map function returns an array. So where is the closure? Can someone explain this?
A function defined inside a function ends up being a closure by definition if local variables are present at the surrounding function and they're used inside the closure.
For example:
function boil(ocean) {
var boiling = 100.0;
return ocean.map(function(h2o) {
return h2o.temp >= boiling ? 'vapour' : 'water';
});
}
The boiling variable here is defined in the main function and used within the function passed to map. Callback functions make the closure behaviour more obvious since they're used in a different context, but the same principle applies.
The "closure" is the callback function. According to MDN:
A closure is the combination of a function and the lexical environment within which that function was declared.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
So when you write something like this:
array.map(function(object) {
// do something
});
That function that you pass in becomes a closure because it gains access to the scope that was present when array.map was called. That's just how JavaScript works.
Thank you all for your responses to the question. With these and the chrome debugger I have come to the conclusion. As Alnitak stated, "
It's a closure iff it accesses variables from that outer scope. Just having the ability to access them is insufficient." This is an important point that I was missing. Also, you can see in the scope section of the sources tab in chrome debugger variables included through closure. So, looking at the following example we can see exactly what closure is:
routerAction: function () {
var name = "alex";
var alex = function(v){
debugger;
console.log("this is var ", name);
}
alex(); // if name was passed and then printed it would be local
// not a closure
}
Functions get their scope from global and local and closure variables.
When you pass "name" into the alex function as a parameter it becomes a local variable so there is no closure. So, if I passed it to alex and console logged "v" where name is, no variables are referenced through a closure. However, since name is defined outside the scope of function alex and then used within, it is scoped through closure (this can be seen in in the scope section of the chrome debugger). By this same logic, if the array that you are operating on (using map or reduce )is defined inside a function, the callback has to form a closure iff the array is referenced inside the callback. If the parameters are just brought in through arguments, none of the variables are accessed through a closure, they are all local variables.
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
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.
I have an object which has two functions within it, and as I guessed each one has a different value for this:
custom_controls : {
play_pause : function () {
console.log(this); // object
videoPlayer.getIsPlaying(function (video_is_playing) {
if (video_is_playing) {
console.log(this); // window
videoPlayer.pause(true);
} else {
videoPlayer.play();
}
});
}
},
Then the function is invoked like this:
custom_controls.play_pause()
I've heard that the way you invoke a function denotes the value of this.
So my question is: What is happening here? What kind of function invocations am I using? And how does each one affect this?
When calling obj.func(), this inside the function will be equal to obj. If there is no obj, the global object (window) is used instead. Or if you are running in Strict Mode, undefined is used.
The first log is your object because you call the function like this:
custom_controls.play_pause() // custom_controls will be 'this'
The second log is window because the function passed as parameter to getIsPlaying is not called with any this:
videoPlayer.getIsPlaying = function(callback) {
callback(); // this inside callback will be window
}
You can control what the value of this will be when you invoke a function by using call or apply. You can create a new function which will always have the this value set to whatever you want by using the bind function:
videoPlayer.getIsPlaying(function (video_is_playing) {
if (video_is_playing) {
console.log(this); // my obj
videoPlayer.pause(true);
} else {
videoPlayer.play();
}
}.bind(this)); // magic!
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Each function is actually executed within a context. That context is denoted as the current this for which you call the function.
Given your code:
If you call custom_controls.play_pause() you are saying "Take the field of the object custom_controls named play_pause and execute it within the context of the object custom_controls".
Later on calling videoPlayer.getIsPlaying() means pretty much the same. Except you're giving it a callback function. How that callback function is executed later on depends on how videoPlayer.getIsPlaying is implemented.
If I have to guess I'd say that getIsPlaying has a callback.call(window, video_is_playing) somewhere in it.
call is a method of all function objects in javascript.
There are a few ways to work around this "issue" if you want to reference a this in some callback.
var self = this;
call_me_maybe(function() {
console.log(this); //the this that call_me_maybe chose to call your function with
console.log(self); //the this from the upper scope
});
or if you don't care about the object in which context call_me_maybe will call your function:
call_me_maybe((function(){
console.log(this); //the this from the upper scope
}).bind(this));
What bind does is it returns a wrap[per of the function which will always be called in the context of the object to which it is bound.
bind can also bind arguments as well as the this object for the function, creating a sort of curry.
Your first this is referring to play_pause.
Your second this could either be referring to the Window or your videoPlayer object. In JavaScript, closures and regular functions are 'generally' attached to window, and calling this returns window. In certain cases, e.g. if you attach a function to the click handler of an HTML element, this refers to the element...
element.onclick = function(){
this // -> element
}
But generally if you just create a function(), or have an anonymous one like yours this refers to window.
function hello(){
this // -> window
}
The this that you've discovered is the object is what you would expect because the function is operating on that object.
I'm not familiar with your videoPlayer, but as the value of this is the "window", I would imagine that either A the video player is a function of the browser itself, or B its scope was not properly closed.
this refers to the "proprietary" of the function, or the object from the function is a method of.
When you define a basic function, the "proprietary" is the page (or the window) itself.
You can check the callback documentation for workarounds
When you call videoPlayer.getIsPlaying it accepts a callback fn. Callback is invoked directly like cb() and hence the context is global (window).
To achieve the callback happening in context of your object. You can use
var fn = cb.bind(customControl);
videoPlayer.getIsPlaying(fn);
As a rule of thumb when a function is called like object.function this is set to object. If function is called directly, this is set to window. Function.bind return a function after binding object (this value) optionally along with parameters.
Read: MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
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);