The following code will allow the counter function to be incremented by one every time counter(); is called.
function One() {
var counter = function(initial) {
var c = initial || 0;
return function() {
return c++;
};
}(0);
Too(counter);
}
function Too(counterArg) {
counter();
}
Is there any thing I can replace counter(); with so the counter will decrement? Or even better is there any way for me to set the value of the counter? Like counter = 0 or counter = 20? Also I need to stay away from global variables.
you can assign function as a variable in javascript so now you can do this...
var counter = 0;
var step = 1; // or 20 or whatever
var method = null;
function increment () {
counter += step;
}
function decrement () {
counter -= step;
}
method = icrement;
method();
First, you have a minor typo in your code; presumably you mean
function Too(counterArg) {
counterArg(); // this was just `counter` originally; that will be undefined
}
Second, c++ is a little bit of a weird way to do a counter, since it return c and then increment c, so the counter will start at 0 which is probably not what you want.
(I admit I chuckle a little bit whenever I see c++ in code though. :P )
Okay, on to the main question: I'd do it by adding a method to the counter function called e.g. set.
function One() {
var counter = function createCounter(initial) {
var c = initial || 0;
function counter() {
return ++c;
}
counter.set = function(n) {
c = n;
};
return counter;
}(0);
Too(counter);
}
function Too(counterArg) {
counter(); // 1
counter.set(20); // `c` is now 20
counter(); // 21
counter(); // 22
}
This works because the counter function creates what's called a closure. This is a fairly common concept in JavaScript and there are plenty of good questions and answers about closures on SO that you should look at if you don't know the concept. Basically, even after your anonymous function (which I renamed createCounter) returns, the variable c still exists and can be accessed from any code in createCounter. That's how the counter function works. c cannot, however, be accessed by any code outside createCounter, so if you want to do anything with it, you have to put that code in createCounter. That's what the counter.set method I added does. Since it's within createCounter, it is free to modify c.
Related
I have the following code I need some clarification with. I want to understand it perfectly before I move on. I know the example might be silly and I am sure there is a lot of better ways to solve the problem but for the sake of this lesson the person used this example.
All I need is some clarification on how exactly the flow of the score function works and onwards. Where are the values coming from? How is it adding up each time the person gives the right answer?
I basically want to understand how this code generates the number to display to the console every time the user inputs a true value into the alert. I am sorry if I'm not coming through clearly, I just need to understand how the code works from function score() and onwards. I could not for the life of me figure it out. Where is sc getting its values from, and where does it pass it too and; and; and.
Is there anyone that's willing to give me a layout of how this code fits together. I would be eternally grateful.
(function() {
function Question(question, answers, correct) {
this.question = question;
this.answers = answers;
this.correct = correct;
}
Question.prototype.displayQuestion = function() {
console.log(this.question);
for (var i = 0; i < this.answers.length; i++) {
console.log(i + ': ' + this.answers[i]);
}
}
Question.prototype.checkAnswer = function(ans, callback) {
var sc;
if (ans === this.correct) {
console.log('Correct answer!');
sc = callback(true);
} else {
console.log('Wrong answer. Try again :)');
sc = callback(false);
}
this.displayScore(sc);
}
Question.prototype.displayScore = function(score) {
console.log('Your current score is: ' + score);
console.log('------------------------------');
}
var q1 = new Question('Is JavaScript the coolest programming language in the world?',
['Yes', 'No'],
0);
var q2 = new Question('What is the name of this course\'s teacher?',
['John', 'Micheal', 'Jonas'],
2);
var q3 = new Question('What does best describe coding?',
['Boring', 'Hard', 'Fun', 'Tediuos'],
2);
var questions = [q1, q2, q3];
function score() {
var sc = 0;
return function(correct) {
if (correct) {
sc++;
}
return sc;
}
}
var keepScore = score();
function nextQuestion() {
var n = Math.floor(Math.random() * questions.length);
questions[n].displayQuestion();
var answer = prompt('Please select the correct answer.');
if(answer !== 'exit') {
questions[n].checkAnswer(parseInt(answer), keepScore);
nextQuestion();
}
}
nextQuestion();
})();
sc gets its value due to closure. When ever the nested function which is returned by score() and the if statement if (correct) is true then score gets incremented. Consider a general snippet below.
function score(){
let sc = 0;
return function(correct){
if(correct){
sc++; //this is the same variable is upper scope.
console.log(sc)
}
return sc;
}
}
let temp = score();
temp(true);
temp(true);
So in the above snippet the outer function score is only called once and does two things:
initialize a variable sc which is 0
return function in which sc will refer to the sc variable created in upper scope.
The use this is just to prevent making of global variable
Consider another simple snippet.
let count = 0;
function counter(){
count++;
console.log(count)
}
counter();
counter();
counter();
In the above snippet the parent scope is global scope and child scope is scope of function. Now the variable count is present inside the the the counter()(even though its not declared inside counter()) due to closure.
Now in the first snippet the function score() is just like global scope(in second snippet),
In first snippet the returned function is return function(correct){...} is just like the nested counter() function in second snippet.
And sc variable is just like count variable.
Could you maybe just explain the prototype.checkAnswer a little bit more
This method takes two arguments. ans and callback.
Consider the line in function nextQuestion()
questions[n].checkAnswer(parseInt(answer), keepScore);
Now if you notice two parameters are passed to function. One is number of correct answer and other is a callback(a function which is passed to another function be be called later).
We are passing keepScore which I explained above is the function returned by score() i.e function(correct){...}. Now this function is called inside the prototype method. This callback returns the value of sc which is declared in its parent function score. And then its displayed using this.displayScore
Now the thing you maybe confused with is the variable sc in the prototype.checkAnswer. That variable is just to prevent the double writing of this.displayScore();
The function can be written as:
Question.prototype.checkAnswer = function(ans, callback) {
if (ans === this.correct) {
console.log('Correct answer!');
this.displayScore(callback(true));
} else {
console.log('Wrong answer. Try again :)');
this.displayScore(callback(false));
}
}
Even if we declare the other variable sc in prototype.checkAnswer it has not relation with the variable sc inside score(). They are completely different variables because the variables declared with var have function scope.
Conisder the snippet:
function score(){
var sc = 0;
return function(){
sc++;
console.log(`I am sc of score: ${sc}`);
return sc;
}
}
let temp = score();
function wrapper(callback){
var sc = 0;
console.log(`I am sc of wrapper: ${sc}`);
callback();
}
wrapper(temp)
wrapper(temp)
wrapper(temp)
wrapper(temp)
It's self-executing wrapper function. It automatically calls nextQuestion() to begin process
var n = Math.floor(Math.random() * questions.length); selects random question from your questions list
displayQuestion() shows information from second new Question() parameter as possible answers. Third parameter is correct answer.
User inputs it's answer in prompt('Please select the correct answer.'); and if it's not exit, then comparing answer with correct value.
After showing answer code calls keepScore(correct) to add score to final result.
[GOTO #2] using nextQuestion();
Here the score function is a Closure
The state of sc inside score is intialised when score is invoked.
var keepScore = score();
Now the keepScore contains the function which is returned by the closure
that is
function (correct) {
if (correct) {
sc++; // it has a "closure" over it
}
return sc;
}
which accepts a boolean value. that is,
keepScore(true) or keepScore(false)
Now this keepScore function is passed to check answer
questions[n].checkAnswer(parseInt(answer), keepScore);
In check anwer, if the answer is correct it will pass true to the keepScore
callback(true) <=> keepScore(true)
If you want to have more clarity on Closure you can go through this article
https://github.com/getify/You-Dont-Know-JS/blob/master/up%20%26%20going/ch2.md#closure
The slightly tricky bit for the uninitiated here is that the score function returns a function and makes use of a closure.
function score() {
var sc = 0;
return function(correct) {
if (correct) {
sc++;
}
return sc;
}
}
This line:
var sc = 0;
creates a variable for holding the current score and then returns a function you can call to increment that variable. The variable can't be declared inside the function because it would get recreated every time the function was called:
// can't do this. sc gets recreated and reset on every call:
function score (correct) {
var sc = 0;
if (correct) {
sc++
}
return sc;
}
But you also don't want the variable available to everyone, so you don't want to do this either:
// don't want this either.
// score shouldn't be modifiable outside of our keepScore method.
let sc = 0;
function score (correct) {
if (correct) {
sc++;
}
return sc;
}
// this approach works, but now cheaters can set
// the score outside our scorekeeping function:
sc = 999999; // oh noes! hacks!
So what can we do? We can:
First: Create the variable within a function scope, where it's protected from outside shenanigans:
function score () {
var sc = 0; // unavailable outside this function
}
Second: Create another function inside the first that can modify the variable:
function score () {
var sc = 0; // unavailable outside this function
// a new function that has access to the outer function's sc variable.
function(correct) {
if (correct) {
sc++;
}
return sc;
}
}
Finally, returning the inner function from score() gives outsiders a way to register correct answers without exposing the score variable itself:
function score () {
var sc = 0; // unavailable outside this function
// return this function to the caller and voila!
// they now have a self-contained scorekeeper function.
return function(correct) {
if (correct) {
sc++;
}
return sc;
}
}
So now when you do this:
var keepScore = score();
keepScore is that inner function with its own internal sc variable.
If you had a multiplayer edition, you could get one for each player:
// each gets their own instance of
// that inner function with its own
// independent sc variable.
const playerOneScore = score();
const playerTwoScore = score();
playerOneScore(true); // 1
playerOneScore(true); // 2
playerTwoScore(false); // 0
playerTwoScore(true); // 1
I think once you understand this bit, the rest will make a lot more sense.
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 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.
So I need a function which increments the value of a variable say n=0. When ever the function runs, the value of this varible must be incremented and it should not be equal to 0 again. For example consider the following code :
function increment(){
var n = 0;
n++;
return n;
}
Now everytime you run this function you get a value of 1. But my requirement is if you run this function for the 1st time, it should be 1, if you run it for the second time, it should be 2 and so on. Unless you refresh the html page and run the function again, it should not be equal to 0. Can anybody help me?
I'm new to coding and any small help is appreciated. Thanks in advance!!!
Create a closure to hold the value
Closures are functions that refer to independent (free) variables.
In short, variables from the parent function of the closure remain bound from the parent's scope.
var increment = (function(n) {
return function() {
n += 1;
return n;
}
}(0)); // -1 if you want the first increment to return 0
console.log(increment());
console.log(increment());
console.log(increment());
You need to declare n outside of the function.
var n = 0;
function increment(){
n++;
return n;
}
The problem is scopes. when you declare a variable inside of a function it is bound to the local scope of the function. as soon as the function is done the variable is gone.
declaring the variable in the root level of the script places it in the global scope.
another way to do this would be to have a variable outside that you're passing around and then you pass it to the function via a parameter.
var i = 0;
function increment(n){
n++;
return n;
}
i=increment(i);
for more information on scopes and variables, review this page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Variable_scope
You can bind the data to the function (since functions are objects).
function increment(){
increment.n = increment.n || 0;
return ++increment.n;
}
What about making the number of times increment was called a parameter ?
function increment(numberOfIncrementCalls){
numberOfIncrementCalls++;
return numberOfIncrementCalls;
}
function increment(numberOfIncrementCalls){
numberOfIncrementCalls++;
return numberOfIncrementCalls;
}
n = document.getElementById("demo");
o = document.getElementById("event");
numOfIncr = 0;
o.addEventListener("click",function(){
numOfIncr = increment(numOfIncr);
var insert = numOfIncr.toString();
n.innerHTML = insert;
});
<html>
<p id="demo"></p>
<button id="event">Click me</button>
</html>
var n = 0;
function increment(){
n++;
return n;
}
Learning about scopes will help you greatly. What you want here is the variable 'n' to be of a global scope.
var n = 0; //Declare n outside of the function makes it accessible to the function
//and to any other functions or expressions that want access to n
function inc() {
n++;
}
You can try this code and store the value in localstorage. All time it will be increase old Value untill you have not clear localstorage...
<script>
localStorage.setItem("n", 0);
increment();
function increment(){
let n;
n = localStorage.getItem('n');
n++;
localStorage.setItem("n", n);
return n;
}
</script>
Every time you call a function the value will be incremented by +1 by this method --
let x = 0;
function increment (){
return x = x + 1;
}
This code will always return 501
a=500;
function increment(n){
return n+1
}
increment(a);
You could equate a to the function
a=increment(a);
That would set a to 501, then 502 etc
However consider using an array for the argument instead
a=[500];
function increment(n){
n[0]++;
}
increment(a);
Now it will increment the value of a[0] even though it doesn't have a return statement. The benefit of this is it means we can have multiple arguments and increment them all, and then return some other variable if you like. Like this
a=[0];
b=[5];
function incrementToTen(n,o)
{
n[0]++;
o[0]++;
if(n[0]>=10||o[0]>=10)
{
return true;
}
else
{
return false;
}
}
So after running incrementToTen(a,b) 5 times it will return true
I am working on a modification of tamper data that will allow me to send the HTTP request/responses it observes to a server. So far, that functionality has been implemented correctly. The next step is to automate this process, and I wish to use a toolbarmenu button of type 'checkbox' to toggle this functionality on and off.
So far I have this bit of code in the .XUL:
<toolbarbutton id="tamper.autosend" label="&tamper.toolbar.autosend;" type="checkbox" oncommand="oTamper.toggleTimer();"/>
And this function in the main driver of my extension:
toggleTimer : function() {
var checked = document.getElementById('tamper.autosend').checked;
var consoleService = Components.classes["#mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(checked);
if (checked) {
var interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
}
Using the consoleService I see that the value of 'checked' is indeed correct. I believe the problem lies with how I am calling clearInterval, but I'm not exactly sure how to remedy it.
Any help is greatly appreciated!
You have defined interval inside if try to declare your variable on the start
var interval = 0;
toggleTimer : function() {
var checked = document.getElementById('tamper.autosend').checked;
var consoleService = Components.classes["#mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(checked);
if (checked) {
interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
}
Your doing it wrong, each time you want to set the new interval you should clear it first
clearInterval(intervalID);
console.log('reset timer');
intervalID = setInterval(function () {
console.log('tick');
}, refreshInterval);
You're storing the interval in a local variable; the value is lost after the function returns, next time you attempt to clearInterval an undefined variable. Store the interval in i.e. a global variable instead:
if (checked) {
window.interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
Ofcourse, because interval is defined as a private variable. It is defined in the toggleTimer function and is destroyed when the function ends.
Use interval = window.setInterval() instead of var interval = window.setInterval() to define a global variable that is accessible later for clearInterval.
Below are some examples of the JavaScript variable scope. var is used to define a variable in the current scope. Leaving var always creates or changes a local variable.
function func1() {
i = 1; // global
}
func1();
alert(i); // 1
var j = 2;
function func2() {
var j = 3; // private
}
func2();
alert(j); // 2
k = 4;
function func3() {
k = 5; // global
}
func3();
alert(k); // 5
var l = 6;
function func4() {
l = 7; // global
}
func4();
alert(l); // 7
function func5() {
var m = 6; // private
}
func5();
alert(m); // undefined