I don't know how to ask correctly what I need, so let me try..
How can I pass a current variable content (literal) to a function dinamically created?
Maybe with this following code you understand better:
function MyClass(){
for (i = 1; i <= 10; i++){
this['show' + i] = function(){
alert('You called show' + i);
};
}
}
var obj = new MyClass();
obj.show3();
What I would like to be displayed in alert is "You called show3" instead of "show11".
Thanks
Since javascript doesn't have a block scope (until let in ECMAScript 6) your original function will be bound with the same value of i.
Calling another that generate itself a new function you avoid that and you give to i different values.
function MyClass() {
for (i = 1; i <= 10; i++) {
this['show' + i] = myFunc(i);
}
}
function myFunc(i) {
return function() {
alert(i);
}
}
var obj = new MyClass();
obj.show3();
There is a mechanism called binding in JavaScript. You can bind scope and any variables to the function in order to use them inside function. Scope will define this keyword inside function. All other binded variables will be available as arguments thus i variable in this example will have not a global but local scope and have a value passed in function creation.
for (i = 1; i <= 10; i++){
this['show' + i] = function(i){
alert('You called show' + i);
}.bind(this,i);
}
Related
I am trying to get around understanding javascript closures from a practical scenario.I know from a theoretical perspective , With the help of closures inner functions can have access to the variables in the enclosing function i.e parent function.
I have read a couple of questions on stackOverflow as well.
i am really missing the point of what is happening here?
var foo = [];
for(var i=0;i<10;i++){
foo[i] = function(){
return i;
}
}
console.log(foo[0]());
This gives me out a 10. Most of the articles say that by the time it reaches the inner anonymous function, The for loop is getting executed as a result the last value that is present in the loop which is 10 is being printed.
But i am still not able to get to the bottom of this.
On Contrary, If i use something like:
var foo = [];
for(var i=0;i<10;i++){
(function(){
var y =i;
foo[i] = function(){
return y;
}
})();
}
console.log(foo[0]());
I am getting the output.Any help would be highly appreciated.
maybe this code block helps
var foo = [];
for(var i = 0; i < 10; i++) {
foo[i] = function() {
return i; // is a reference and will always be the value, which 'i' have on function execution
}
}
// 'i' is 10 here!
console.log(foo[0]()); // executing the function will return the current value of 'i'
///////////////////////////////////////
var foo = [];
for(var i=0;i<10;i++) {
/* thats a IIFE (immediately invoked function expression) */
(function(a) { // 'a' is now a local variable
foo[a] = function() { // defines a function
return a; // is a reference to local variable 'a'
};
})(i); // <- passing the current value of i as parameter to the invoked function
}
// 'i' is 10 here
console.log(foo[0]()); // returns the reference to 'a' within the same scope, where the function was defined
In your first scenario, all of your functions added to the foo array are referencing the same var i. All functions will return whatever i was set to last, which is 10 because during the last iteration of the loop that's what it's value was set to.
In the second scenario, you are Immediately Invoking this function:
(function(){
var y =i;
foo[i] = function(){
return y;
}
})();
By immediately invoking it you are effectively locking in the local state of var y, for each iteration of the loop - it provides a unique scope for each function added to the array.
I read the How do JavaScript closures work? question and thought i finally understood closures.
Especially this point is very confusing right now:
Example 7
This final example shows that each call creates a separate closure for the local variables. There is not a single closure per function declaration. There is a closure for each call to a function.
..........................................
Ok, so Example 7 shows this example:
function newClosure(someNum, someRef) {
// Local variables that end up within closure
var num = someNum;
var anArray = [1,2,3];
var ref = someRef;
return function(x) {
num += x;
anArray.push(num);
document.write('num: ' + num +
'; anArray: ' + anArray.toString() +
'; ref.someVar: ' + ref.someVar + "<br>");
}
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;
This example works for me as it should.
So I experiemented a little and i don't really understand why this code doesn't work (looks like it doesn't even create a new closure on function call)
function createCounter(startValue){
var localCounter;
this.setCounter = function(firstValue) {
localCounter = firstValue;
}
this.getValue = function(){return localCounter;};
this.increment = function(){localCounter++;};
this.setCounter(startValue);
return this;
}
var Counter1 = createCounter(1);
document.write(Counter1.getValue()); //1
Counter1.increment();
var Counter1Value = Counter1.getValue(); // 2
var Counter0 = createCounter(0); //works as it should if i put a "new createCounter(0) here, but why?
document.write("<br >Counter 1 oldValue:" + Counter1Value); //2
document.write("<br >Counter 1 currentValue:" + Counter1.getValue()); //0 (why is the localvariable overwritten?)
document.write("<br >Counter 0 currentValue:" + Counter0.getValue()); // //0
why do i need to add the "new" keyword to create a second closure, and why are both Counter1 and Counter0 using the same localCounter variable?
As elclanrs says, it is all about this:
When you call createCounter(1), this is unchanged, most likely remaining the global scope. Given document.write, it's safe to say the global scope is window. So, you create window.setCounter as a function that will set localCounter, a variable hidden in a closure, and window.getValue to a function that reads this hidden variable; it initialises localCounter to 1; it then returns window and assigns it to Counter1.
Then, Counter1.getValue() calls window.getValue(), which returns 1. All good. Same with increment.
However, since you are operating on the global context all the time, when you do createCounter(0), you are overwriting window.getValue (and other functions) with a new closure that now references a different hidden localCounter, this one initialised to 0. Since both Counter0 and Counter1 point at the same object (namely, window), it is not too farfetched that Counter1.getValue() and Counter0.getValue() should also return the same thing (given that they both have no side-effects).
This changes drastically with the new keyword, which is one of the several ways in JavaScript to change what this is. If you do var Counter1 = new createCounter(1) and var Counter0 = new createCounter(0), this inside the function is a new object in both cases; and Counter1 has different closures on it than Counter0.
Specifically, new createCounter(0) will do something like this pseudocode:
var oldThis = this; // save current context
this = {}; // make a new object
createCounter(0); // initialize the new object
this = oldThis; // restore current context
so you can see why the values are kept distinct.
Take a look at the following code
//btns is an array passed as a parameter to a function
for(var i = 0, b; b = btns[i]; i++) {
b.handler = function () {
var a = btns[i].some_field; //undefined
//the same for "b.some_field;"
};
}
Why btns[i] is undefined?
PS. the code adds click handler on extjs buttons if that matters.
This happens because by the time the inner function is called (which is after the loop is done) the value of i would be btns.length and therefore the value of btns[i] would be undefined.
You need to close over the value of i like this:
b.handler = function(i) {
return function() {
var a = btns[i].some_field;
}
}(i);
It's important to note that although the variables have the same name, they're different variables; i.e. the inner variable shadows the outer, thereby "fixing" the value.
for(var i = 0, b; b = btns[i]; i++) {
b.handler = function () {
var a = this.btns[i].some_field;
//the same for "b.some_field;"
};
}
give "this." in side the function we have to use "this" to point
I just write a test html file to learn about object in javascript. The code is as follows
in script tag
<script type="text/javascript">
var obj = new ParentFn();
var obj2 = new AnotherParentFn();
var temp;
function initer()
{
temp = obj.Adding();
obj2.caller();
}
function ParentFn()
{
this.a = 10;
this.b = 20;
}
function AnotherParentFn()
{
this.a = 30;
this.b = 50;
}
AnotherParentFn.prototype.caller = function()
{
var self = this;
temp();
}
ParentFn.prototype.Adding = function()
{
var self = this;
document.getElementById("id_div1").innerHTML = " Method Called and Result of a+b is " + (self.a + self.b);
}
</script>
In body i use
<button onclick="initer()"> Click here to test </button>
<div id="id_div1"></div>
Problem is when AnotherParentFn.prototype.caller is called from initer() function temp variable is still undefined. What is wrong with the code??
My task is to assign the function ParentFn.prototype.Adding in a global variable and call the global variable from AnotherParentFn.prototype.caller function. How to achieve it?
You don't need to save it as a global variable. It's already saved in ParentFn.prototype. All you need to do is invoke it with .call and pass in your desired receiver. You can implement AnotherParentFn.prototype.caller like this:
AnotherParentFn.prototype.caller = function()
{
ParentFn.prototype.Adding.call(this);
}
This way you can get rid of temp completely. You also don't need to assign this to a local var self everywhere.
Parentheses are used to execute a function.
When you assign the value to temp, you are calling the function and assigning the result (undefined) to temp. To store a reference to the function in temp, omit the parentheses.
temp = obj.Adding;
By writing temp = obj.Adding(); it stores the return value. not function pointer in temp. Use this
function initer()
{
temp = obj.Adding;
obj2.caller();
}
First of all, the reference to obj.Adding is not assigned properly; it should be this (without parentheses):
function initer()
{
temp = obj.Adding;
obj2.caller();
}
Then, inside AnotherParentFn.prototype.caller itself, you must pass the current object as this explicitly during the invocation by using .call():
AnotherParentFn.prototype.caller = function()
{
temp.call(this);
}
If I declare a function literal:
var x = function(){
alert('hi');
};
console.log(x); // returns the function code.
However:
var x = (function(){
alert('hi');
})();
console.log(x); // returns undefined?
I don't understand why this happens. Isn't the point of writing a function as a literal is to still be able to access it by its variable reference name? I know this may be silly but I'm just learning javascript so don't judge too harshly.
Your function does not return anything, so its return value is undefined.
A self-executing function is executed and the function is not stored anywhere - only its return value survives (and any external variables the function sets/modifies).
For example, this code would be equivalent to var x = 'hi';:
var x = (function(){
return 'hi';
})();
The purpose of self-invoking functions is usually to create a new scope, e.g. when creating callback functions in a loop:
for(var i = 0; i < 5; i++) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
}
This would use the same i in all callbacks so it would alert i = 5 5 times.
for(var i = 0; i < 5; i++) {
(function(i) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
})(i);
}
By using a self-executing function we create a new scope and thus a new i in each loop.
Another use of self-executing functions is to create a new scope where certain variables are ensured to be available and set to the correct value:
(function($, window, undefined) {
// here the following always applies:
// $ === jQuery
// window === the global object [assuming the function was executed in the global scope]
// undefined is well, undefined - in some js engines someone could have redefined it
})(jQuery, this);
If you:
var foo = somefunction;
… then you assign a function to foo.
If you:
var foo = somefunction();
… then you assign the return value of a function call to foo
Your function:
function(){
alert('hi');
}
… has no return statement, so it will return undefined.