I'm trying to call a function without re-initializing (hope I used the correct word here) it every time I call it. So the first time it gets called, it should initialize, but after its initialized, it should just use that reference.
Here's the code I'm trying to do it with.
JSFiddle
console.clear();
function mainFunction(e) {
var index = 0;
function subFunction() {
console.log(index++);
}
return subFunction();
}
window.addEventListener('click', mainFunction)
index should increase by one every time mainFunction gets called. The obvious solution, is to make index a global variable (or just out of mainFunction). But I need index to stay inmainFunction`.
How can I make index increment every time (using the same reference) mainFunction gets called?
I tried assigning mainFunction to a variable, then calling the variable in the event listener,
var test = mainFunction;
window.addEventListener('click', test)
but that didn't work. The results were the same.
You should correct the code as follows;
console.clear();
function mainFunction(e) {
var index = 0;
function subFunction() {
console.log(index++);
}
return subFunction; // <<< don't invoke subfunction
}
window.addEventListener('click', mainFunction()) // <<< invoke mainfunction
maybe try closures?
var main = (function () {
var index = 0;
return function () {return index += 1;}
})();
main()
main()
//index should be 2...
explain-
The variable main is assigned the return value of a self-invoking function.
The self-invoking function only runs once. index initialize only once.
If you don't want to make index global (or one scope higher regarding mainFunction), you can use a closure:
var mainFunction = (function () {
var index = 0;
return function () {return console.log(index++);}
})();
<button onclick="mainFunction()">Click</button>
Using OOP concept is the proper way to achieve this. The following should help you.
If you want to do it in ES6 way follow this babel example
var mainFunction = function(val) {
this.index = val //initialize this with the fn parameter or set a atatic value
}
mainFunction.prototype.subFunction = function() {
return this.index++
}
var instance = new mainFunction(0)
window.addEventListener('click', function() {
console.log(instance.subFunction())
})
<p>Click to see the result </p>
Related
I'm not sure if what i am trying to do is possible, or if there's an easier way to do what I'm trying to do.
I have the following code:
<script>
function TitleSwitch() {
var counter = 0,
fn = function () {
var array = ['Value1','Value2','Value3'];
$(document).prop('title', array[counter]);
counter++;
counter %= array.length;
};
fn();
return fn;
}
setInterval(TitleSwitch(), 5000);
</script>
It rotates the page title between the three variables, Value1, Value2, and Value3 every 5 seconds. This is working fine.
However, on the same page there is some ajax script that is polling for other information related to the app.
What I am trying to do is use some of the data returned from the polling script to change the values in the title switching function.
So, as an example, the poll data may return Value4, Value5, and Value6 instead.
So in the code above, is there any way to replace the values in
var array = ['Value1','Value2','Value3'];
from another function, outside of the title switching function?
So, say I have a function called pollingDone() that is called each time the polling data is returned, how can I change the values of "array" in TitleSwitch() from within pollingDone() after TitleSwitch() is already running using setInterval?
basically, what I was trying to do is keep TitleSwitch running, but just replace the values used.
The reason I was trying to do it this way is because the titles are switched between the three values every 5 seconds, however the polling script runs every 10 seconds. So if I started the TitleSwitch() function over each time the polling script completes, the third value would never be shown in the title. The first two would show, the polling script would run, and then the titles would start over. So I was hoping to keep the TitleSwitch() function running as-is, and just replace the values it is using.
You can do that by exposing the array in the fn function to the outside context.
Here is an example:
function TitleSwitch() {
var counter = 0;
this.array = ['Value1','Value2','Value3'];
var self = this;
this.fn = function () {
$(document).prop('title', self.array[counter]);
console.log(self.array[counter]);
counter++;
counter %= self.array.length;
};
this.fn();
}
var switcher = new TitleSwitch()
setInterval(switcher.fn, 500);
function asyncFn(){
switcher.array[0] = "changed title1";
}
setTimeout(asyncFn, 1000)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Pass it in the constructor so you can control the access level from outside.
In the example:
myArray is defined outside the closure that TitleSwitch creates.
When editing its values, the next iteration will use the updated contents.
Like so:
function TitleSwitch(array) {
var counter = -1,
fn = function () {
counter++;
counter %= array.length;
// Move to bottom to prevent errors when using a shorter array
console.log(array[counter]);
};
fn();
return fn;
}
var myArray = ['Value1','Value2','Value3'];
setInterval(TitleSwitch(myArray), 1000);
myArray[1] = "TEST";
myArray[2] = "TEST2";
I think you will have to get your variable out of your function scope, something like this:
var titles = ['Value1', 'Value2', 'Value3'];
function TitleSwitch() {
var counter = 0,
fn = function () {
$(document).prop('title', titles[counter]);
counter++;
counter %= titles.length;
};
fn();
return fn;
}
setInterval(TitleSwitch(), 5000);
// Here, you can modify your titles in an ajax call
There is no way to replace array that is defined as a local variable inside fn. If you pull it out to outside of TitleSwitch, you can just give it a new value. Alternately, you can use a property on fn, or construct a more complex object, to avoid polluting the environment.
You also want to raise the modulo line to the start of fn: e.g. if you have a 5-element list with counter being 4 and you replace array with a 2-element list, your code would break.
var array = ['Value1','Value2','Value3'];
function TitleSwitch() {
var counter = 0,
fn = function () {
$(document).prop('title', array[counter]);
console.log(array[counter]);
counter++;
counter %= array.length;
};
fn();
return fn;
}
setInterval(TitleSwitch(), 5000);
function pollingDoneCallback(data){
if(data){
array=[];
for(var i=0;i<data.length;i++)
array.push(data[i]);
}
}
pollingDoneCallback(['val5','val6']);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm newbie in JS, and in this JS closure example
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
I can't get why the variable add is assigned to the invocation of the function, not the function itself.
In other words, now add is supposed to be referencing an invoked function, and to call add, we don't need to add () at the end, it is already called.
Why does the example call it like this: add() ? I can't find the exact term for it, but isn't this like 'double calling' the function ?
take a look at this code
function createCounter(){
var index = 0; //initialize the index
//returns a closure that increments the index,
//and returns the value on every invocation
return function(){ return ++index; }
}
//crete an "instance" of a counter
var aCounter = createCounter();
//and invoke it a few times
console.log("a", aCounter());
console.log("a", aCounter());
console.log("a", aCounter());
//create another counter, and invoke it
var anotherCounter = createCounter();
console.log("b", anotherCounter());
console.log("b", anotherCounter());
//showing that they increment independent of each other
console.log("a", aCounter());
console.log("a", aCounter());
that would be a "good" implementation of this utility, because you can use it over and over again, without repeating yourself.
If you invoke createCounter directly, you get your code-example.
var aCounter = (function(){
var index = 0;
return function(){ return ++index }
})();
I am trying to learn about closures in javascript and I came across the following example:
function counter() {
var count = 0;
return function() {
alert(count++);
}
}
var count = counter();
count();
count();
count();
Which makes sense to me, my question is, why doesn't this work?
var count = function() {
var count = 0;
return function() {
alert(count++);
}
};
count();
count();
count();
To me it seems like it should be the exact same thing but maybe I'm just missing something obvious, please assist.
In order for your second method to work, you will need to call the returned function like this:
var count = function() {
var count = 0;
return function() {
alert(count++);
}
};
count()();
However, doing this, your count number will not increase because it is not being stored anywhere like in the first example, where the variable count holds the function.
So if you want to retain the value of count, use the first method where you say var count = counter()
Hope that clears things up!
I'll try to give a nice explanation right in your code:
function counter() {
var count = 0;
// By calling the function counter (adding a '()' after its name) you are returning a brand new anonymous function
return function() { // **Reference 1**
alert(count++);
}
}
// Here, the count variable is actually the anonymous function you returned in the **Reference 1**
var count = counter();
// In this line, you are calling the anonymous function (adding the '()' after its new name 'count')
count();
The explanation above explain why this works. Because, first you called a function which returned an anonymous function and assigned it to the variable count. Then you called that function by adding the '()' after its name, which executes the alert(count++)
Now, why the other example does not work? I guess it's pretty obvious now:
var count = function() {
var count = 0;
return function() { // **Reference 2**
alert(count++);
}
};
// Here you are calling the count function which returns the anonymous function in the line **Reference 2**.
count(); // So, long story short, this call only returns the anonymous function.
You should try to add a second '()' after it: count()();. This should work as well, because the first '()' returns the anonymous function, and the second one, executes the anonymous function returned.
Hope this helps!
Before you can use the closure, you have to call the outer function to create the closure and get the inner function that is returned and then retain that return result that you can then call subsequent times to use the closure. So, in your second example, you have to call count() and retain it's return result and then use that return result for subsequent calls.
Your second example will work if you change it to this (which looks pretty much the same as the first example):
// log output for purposes of the snippet
function log(x) {
var div = document.createElement("div");
div.innerHTML = x;
document.body.appendChild(div);
}
var counter = function() {
var count = 0;
return function() {
log(count++);
}
};
// get the inner function and create the closure
var count = counter();
count();
count();
count();
As you can see this only differs from your first example in that counter is a function expression instead of a function definition. Other than the timing of when counter is defined, the second code example is no different and thus the implementation needs to be the same.
This is regarding javascript closures working.
I have a function inside another and I want to access this outside of the outer function.
is it possible since it written here that u can achieve closure with this
http://www.w3schools.com/js/js_function_closures.asp
JavaScript Nested Functions
All functions have access to the global scope.
In fact, in JavaScript, all functions have access to the scope "above" them.
JavaScript supports nested functions. Nested functions have access to the scope "above" them.
In this example, the inner function plus() has access to the counter variable in the parent function:
Example
function add() {
var counter = 0;`enter code here`
function plus() {counter += 1;}
plus();
return counter;
}
I am trying to acess plus() from outside
Agree with Grim.
But if you wanna access to plus function outside, you can try this way:
function add(){
var counter = {
value: 0,
plus: function(){
return ++this.value;
}
};
counter.plus();
return counter;
}
Hope it helps.
You cannot. An inner function is only available within the body of the outer function.
I assume your target is to keep value as private property inside add and provide manipulations to it via add.plus() calls:
//define your object with a private "value" and a public modifier "plus"
var add = (function() {
var counter = 0;
var that = {
plus: function() {
return counter++; //equal to your code
}
}
//your integrated first call
that.plus();
return that;
})();
//make a call
add.plus();
DEMO - Working code example.
This may be what you are looking for, especially as related to the tutorial link you provided. It is a step in the right direction.
var plus;
add();
plus();
plus();
plus();
alert(plus());
function add() {
var counter = 0;
plus = (function(counter) {
return function() {counter += 1;return counter;};
})(counter);
plus();
}
It is a straight forward example of closure. I made plus a global variable, but alternatively add() could return the function definition of plus. I took the return value away from add() and moved it to plus(), as with this code counter will always equal 1 when add() is finished.
However, and directly from the tutorial you mentioned, the best way to achieve what they are attempting is with this code, ripped directly from their web page.
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add(); // the counter is now 3
I'm not sure my question is understandable. I don't know of a better way to explain it without an example.
Let's assume I have the following code:
function foo(obj){
var index = 0;
obj.onstart = function(){
++index;
console.log('start', index);
}
obj.onfinish = function(){
console.log('finish', index);
}
}
Now let's assume I have the following test case:
foo(slow_connection);
foo(fast_connection);
Basically, the onfinish of slow_connection is triggered after the onstart of fast_connection causing the following output.
start 1
start 2
finish 2 <-- This should be 1!
finish 2
PS: I can't change the arguments of foo() the only code I can change is inside foo().
Something like this maybe:
function foo(obj){
var index = 0;
obj.onstart = function(){
++index;
console.log('start', index);
};
// bind onfinish using a "copy" of the current index.
obj.onfinish = (function (idx) {
return function () {
console.log('finish', idx);
};
}(index));
}