Is the JSlint warning `redeclaration of var counter` necessary? - javascript

I have a script that's several lines long and I have a lot of flag types like so
var counter = 0;
var carFlags = {
Audio : counter++ ,
Bentley : counter++ ,
Chrysler : counter++
Datsun : counter++
...
};
later if I create a new flag object the same way
var counter = 0;
var nameFlags = {
Ashley : counter++ ,
Bronwyn : counter++ ,
Catherine : counter++
DakotaFanning : counter++
...
};
It complains that counter is used as part of a greater statement, but I think it's perfectly acceptable here. However, I have used counter twice here, so it warns of redeclaration of var counter. I could move var counter to the top of the page, but that might make it less clear what counter is used for. Is there any real problem with using var more than once? I had a delete counter statement but it did nothing. Should I change it to delete window.counter?

I am not quite sure about your scope here, but if it's global scope then delete counter would indeed do nothing. There is also no need to delete window.counter which will is the same thing anyway (if we are in a browser environment in global scope).
If you wish to re-use the variable - a simple assignment would do:
counter = 0
The reason JSLint complains is, I believe, to warn you that you might have meant to re-use the counter and accidentally typed var (happened to me more than once).
There is absolutely no harm in declaring the same variable twice (aside from increasing slightly the size of the JS file your users' browsers would have to download when loading your page) in the same scope.
EDIT:
there is, of course, a question of why would you use the same name...

No, there isn't a problem. In fact, in Javascript, variable declarations (with var) are automatically hoisted to the top of their enclosing scope anyway. For example, the following:
var n = 5;
if (n &lt 3) {
var q = 2;
var n = 4;
}
is equivalent to:
var q, n=5;
if (n &lt 3) {
q = 2;
n = 4;
}

Give them unique names and you won't have any problem.
var carCounter = 0;
var nameCounter = 0;
Nor will you end up with any hard to find bugs because you used the same variable for two different tasks.

Related

How to fix that when variable is compared it becomes undefined in JavaScript?

I'm creating a small game as a test for my JavaScript skills. For some reason I cannot figure out, when I compare the variable iron and the variable drill, drill becomes undefined, and listed as NaN in my webpage.
I'm using Javascript and HTML on repl.it. I feel it may be an issue with my If statements, but I'm not sure how to fix them if that is the source of the issue. Also, the variables iron and drill are set to 0 default.
if (iron < drillPrice) {
alert("Not enough iron");
}
if (iron >= drillPrice) {
drill = drill + 1;
tempDrills = drill
iron = iron - drillPrice;
document.getElementById('drillsOwned').innerHTML = drill;
iron = Math.round(iron * 10) / 10;
document.getElementById('ironOwned').innerHTML = iron;
drillPrice = Math.floor(100 * Math.pow(1.1, drill));
document.getElementById("drillPrice").innerHTML = drillPrice;
}
}
The full repl is here: https://repl.it/#Munix/factory
The output expected if the variable iron is higher then the variable drillPrice, it should make drill one higher, in this case making drill equal 1. What actually happens is drill becomes undefined. If the variable iron is lower than drillPrice, it should display the test Not enough iron, and not touch the variable drill. What actually happens is it displays the test Not enough iron, but sets drill to undefined.
The issue is this part of the code:
function randomEvent() {
var event = Math.random();
event = Math.round(event * 10);
if (event <= 9) {
document.getElementById("event").innerHTML = "No event today!";
drill = tempDrills
}
if (event == 10) {
var eventFlavor = 'You have iron deficiency! 1/2 iron from drills for the rest of the day!';
document.getElementById("event").innerHTML = eventFlavor;
var tempDrills = drill;
drill = drill / 2;
}
}
What we see here, is an example of how variables are created in javascript:
var tempDrills = drill;
The declaration of the variable is hoisted to the top of the function, so it basically looks like this:
function randomEvent() {
var event = Math.random();
var tempDrills;
...
}
So the variable gets hoisted and will not be set to the value of drill, unless you are lucky enough to roll the 1 in 10 on startup. So tempDrills is a local variable with the value undefined in the other 9 cases, explaining the behaviour once you set drill back to tempDrills.
The solution is silmply to remove the var keyword, so you use the global variable instead. Then it works as expected for me.
I have figured out my own question, thanks to #Shilly's comment. I had a drill = tempDrills at the incorrect time, causing it the variable drill to become undefined. By removing this, I managed to get the code to work.

JavaScript For Loop Breaking Early

Why would a for loop terminate early in JavaScript? For some reason my outer for loop terminates after the first repetition. I am new to JavaScript but would expect something like this to work in Java.
function check(){
var elements = document.getElementById('fields').children;
var filteredMolecules = molecules;
console.log(elements.length);
for (i = 0; i < elements.length; i++) {
console.log(elements[i].id)
filterMolecules(filteredMolecules, elements[i].id, 0, 10);
}
}
function filterMolecules(molecules, parameter, lower, upper){
console.log('filtering');
var filteredMolecules = [];
for (i=0;i<molecules.length;i++){
var value = molecules[i].val()[parameter];
filteredMolecules.push(molecules[i]);
}
molecules=filteredMolecules;
}
In check(), I loop through elements which contains 22 items as shown by the first console.log(elements.length). If I remove the method filterMolecules(...) then all 22 IDs are logged. However, with the code as is, only the first id is logged.
I believe the filterMolecules method which should run elements.length number of times is causing the outer for loop to not work. Could someone please explain why this is happening. If relevant, in filterMolecules(...) the data is retrieved from Google Firebase with molecules[i].val()[parameter]. Additionally, both methods use the global variable molecules (line 3 and line 14)
When you don't declare variables in javascript you end up using globals (which can be a difficult to spot source of bugs). So here you are using the same global variable i for both loops. When you start looping thought molecules you are accidentally incrementing the counter loop of your first for. Use different variables or define them with :
for (let i=0;i<molecules.length;i++)
Which will give each loop its own version of i.
In this case, since the declarations are inside individual functions, you could use var too:
for (var i=0;i<molecules.length;i++) {
// etc.
}

javascript: var i is not defined? (clearly defined)

WHAT I WANT TO HAPPEN
So what I want to happen is function partA() to click button [z] every 2 seconds. The button that is being clicked should change, because the script is a looping script, so for instance. The first loop, it would click button 1, then button 2, then button 3, because var z = 1 + i++. Is this possible? z is supposed to equal the number 1, plus the loop number. This should loop as long as variable i is less than 50.
WHAT IS HAPPENING
It works properly, looping and all, if I test the script without variable z. However, without variable z, I have to manually change the number that would equal z, which is painstaking, and annoying.
var z = 1 + i++
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
}
Should i++ be defined another way? The error I'm getting when running the script in console is:
Uncaught ReferenceError: i is not defined (...)
at :2:13
at Object.InjectedScript._evaluateOn (:878:140)
at Object.InjectedScript._evaluateAndWrap (:811:34)
at Object.InjectedScript.evaluate (:667:21)
There's a couple of suggestions I could advise with your code so I'll try and address each one individually.
Firstly define your function outside of your loop. If you would like to know the reasons behind this please read: Don't make functions within a loop
Secondly you should really declare i as a variable to set the scope to which it applies. Some good information on this is at: Declaring variables without var keyword
Thirdly when you run your loop you could run the code inside an IIFE. The reason for this is when you run setInterval, by the time it runs i will actually be 3 (or the last number of your loop). This is due to the asynchronous nature of setInterval, and that the reference to i is bound to the function, not the value of i.
Example
for(var i=0;i<3;i++) {
(function(i) {
setInterval(clickButton(i), 2000);
})(i)
}
function clickButton(idx) {
return function() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[idx].click();
}
}
JSBin Demo
http://jsbin.com/harigewuze/edit?html,js,output
Why are you trying to define z outside the loop? Just use i.
for (var i = 0; i < 50; i++) {
...
document.getElementsByTagName('button')[i].click();
}
without changing your code too much I would write it like this...
you know its looping 50 times, you know i is incrementing from 0 to 49, use i to change the button name and you don't need z...
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[i + 1].click();
}
}
1) This is how you want your code to look like :
var z;
for(i=0;i<50;i++) {
z=i;
setInterval(partA, 2000);
}
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
2) Unfortunately, in javascript you have a problem with this code due to the fact of scopes. My recommendation is to read this link first http://www.mennovanslooten.nl/blog/post/62 and understand how it works.
If you did understand it, then thumb up..you just promoted yourself to a higher level in javascript ;)
3) If you are still having issues, post it on JSFiddle

Javascript: TypeError variable is undefined

I am currently building a small web application with similar functionality across all modules. I want to code small generic functions so that all programmers next to me, call these functions and these functions return necessary but important data for them to implement their functionality. In this example, I am trying to deal with the typical "choose true or false" exercise. So from the template.php they call this function:
function checkAnswers(){
var radiobuttons = document.form1.exer1;
var correctAnswers = answers(); //this is an array of string
var checkedAnswers = checkExerciseRB(radiobuttons, 2, correctAnswers);
for(i=0; i<checkedAnswers.length; i++){
alert(checkedAnswers[i]);
}
}
Function checkExerciseRB is my generic function, it is called from checkAnswers.
function checkExerciseRB(rbuttons, opciones, correct){
var answers = new Array();
var control = 0;
for(i=0; i<rbuttons.length; i++){
var noPick="true";
for(j=0; j<opciones; j++){
if(rbuttons[control+j].checked){
if(rbuttons[control+j].value==correct[i]){
answers[i]= 1;
noPick="false";
break;
}
else{
answers[i]=2;
noPick="false";
break;
}
}
}
if(noPick=="true")
answers[i]=0;
control=control+opciones;
}
return answers;
}
It works great but while looking at my favorite browsers (FireFox, Chrome) error log it says:
TypeError: rbuttons[control + j] is undefined
Any clue on how to deal with this matter?
This probably means that control + j is greater than or equal to the length of the array rbuttons. There's no such array element as rbuttons[control + j].
You should learn how to use the JavaScript debugger in your favorite browsers! Debuggers are great. They let you watch this code run, line by line, as fast or as slow as you want, and watch how the value of control changes as you go.
You’ll watch it, and you’ll think “Oh! That line of code is wrong!”
You're looping through rbuttons.length times, but in each loop you're adding 2 to control. Using control to index your array, you're going to run past the end.
Does the index specified by control + j exist in the array? i.e: If that evaluates to 4, is there at least 5 items in the array?
Also, you should be using var i, var j, etc inside your for loop. Without it your variables are leaking into the scope this code is executed in (most likely the global scope, and that's not good) :)

global variables javascript, which is faster "varname" or "window.varname"

var testvar = 'boat';
function testA() {
console.log(testvar);
}
function testB() {
console.log(window.testvar);
}
I know that if I don't put the "window." for my global variable, then javascript searches all the scopes from method testA onward until it finds the variable testvar, so if I do window.testvar instead does it make it faster because I'm directly telling javascript which scope to look in for the variable? Or slower because I'm first telling javascript to look for the window object and then the variable?
Try both of the codes below separately and see the results for yourself. Indeed this might not be the most accurate testcase however by avoiding all other manipulation and doing a simple assignment inside a long enough for loop it ought to be accurate enough.
I have to say I was also surprised to see that by not specifying window Chrome persistently reported about 20% faster execution for the second code.
CODE 1
// window.testvar testcase.
window.testvar = 'Hi there! I am a testvar!';
var tmp;
var start = new Date();
for(var i = 0; i < 1000000; i++){
tmp = window.testvar;
}
var stop = new Date();
console.log('This took exactlly ' + (stop.getTime() - start.getTime()) + ' milliseconds!');
RESULTS:
1695ms
1715ms
1737ms
1704ms
1695ms
CODE 2
// direct testvar testcase
testvar = 'Hi there! I am a testvar!';
var tmp;
var start = new Date();
for(var i = 0; i < 1000000; i++){
tmp = testvar;
}
var stop = new Date();
console.log('This took exactlly ' + (stop.getTime() - start.getTime()) + ' milliseconds!');
RESULTS:
1415ms
1450ms
1422ms
1428ms
1450ms
Tested in Chrome 20.0.1132.47.
Vedaant's jsperf was not helpful. It was only creating functions, not executing them. Try this one: http://jsperf.com/epictest/9. It too shows that not specifying window is faster. I also added a test to show that copying to a local variable is dramatically faster. Vary the loop counter to see that you win for anything more than a single reference to the global.
Chrome has a useful javascript CPU profiler. Just create a loop to run the function several thousand times and start the profiler. I'm guessing that the difference is very small but this would be a good way to know for sure.
I just made a jsPerf test for you, check it out at: http://jsperf.com/epictest. It seems that
function testA() {
console.log(testvar);
}
is a bit faster.

Categories

Resources