JSLint Error Report - Whats wrong with this? - javascript

I got this error and dont know what could be the cause. Any idea?
Problem at line 2127 character 18: Bad for in variable 'sport'.
for (sport in sugested_sports)
// make array
var sugested_sports = data.split(",");
// pre build DIV
var sporty_items = '';
for (sport in sugested_sports)
{
if (sugested_sports.hasOwnProperty(sport)) {
sporty_items += ''+sugested_sports[sport]+'';
}
}
// insert DIV
DIVsuggestions.html(sporty_items);
thx alot.

Try
var sport;
for (sport in sugested_sports)
This takes care of the missing variable declaration and places it outside the for loop ( see jsLint error "Cannot set property 'first' of undefined" ).

Pointy's answer is probably the one that lint is complaining about.
As a general rule you though, you should be careful when using for (... in ...). People often confuse this construct with foreach from C#, or other similar concepts in other languages, when in fact it isn't related. The javascript for in construct iterates every member of the object -- rather than just values in a collection -- including methods and properties. This behaviour can often lead to unexpected side effects if you aren't aware of how it works beforehand.
For example:
x = ['one', 'two'];
for (var value in x) {
alert(value);
}
That yields two alerts, the first contaning 0 and the second 1, notably the indexes of the collection.
If we change that up a bit:
x = ['one', 'two'];
x.method = function() {};
for (var value in x) {
alert(value);
}
We end up with three alerts this time, 0, 1, and method. This is the unexpected behaviour I was referring to. It's fine to use in if you know what it does, but I've seen it catch people out on more than one occasion.
The following works with both examples:
x = ['one', 'two'];
for (var i = 0; i < x.length; i++) {
alert(i);
}

All the error means in JSHint/JSLint is that you didn't declare your key/iterator variable. As #Christopher suggests, JSLint wants you to declare it at the top of its scope (google JavaScript hoisting for more on hoisting, like this link):
/*global data, identifier, DIVsuggestions */
// We'll pretend all of the above were passed in from a function's parameters
// by using JSLint's "global" keyword -- now you can paste this code into
// jslint.com and have it pass muster.
// make array
var sugested_sports = data.split(","),
sporty_items = '', // pre build DIV
sport; // <<<< **** DECLARE YOUR "KEY" HERE ****
for (sport in sugested_sports)
{
if (sugested_sports.hasOwnProperty(sport)) {
sporty_items += '<a href="#'+identifier[1]+'">'
+sugested_sports[sport]+'</a>';
}
}
// insert DIV
DIVsuggestions.html(sporty_items);
This bad for in variable error here reduces to the same as a 'sport' was used before it was defined error elsewhere.
EDIT: It's worth mentioning that if your for is in an internal function, you need to declare your for in variable in that same context. JSLint will complain if you declare the for in in the parent context.
Example:
function spam(d)
{
var fnTest, row; // `row` is defined "too early"
fnTest = function (data) {
for (row in data)
{
if (data.hasOwnProperty(row))
{
console.log(data.row);
}
}
};
fnTest(d);
}
To make things happy, move row into the internal function. Even though it was technically still in scope, JSLint doesn't like the "superscope" that was used before.
function spam(d)
{
var fnTest;
fnTest = function (data) {
var row; // and JSLint is happy! ;^D
for (row in data)
{
if (data.hasOwnProperty(row))
{
console.log(data.row);
}
}
};
fnTest(d);
}
By the way, James' concern is covered by the hasOwnProperty check the OP has inserted. Take out that check, and JSLint will complain, "The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype". Here's a little more on hasOwnProperty with for... in, if you're interested.

var sugested_sports = data.split(","),
sport,
sport_items = '';
for (sport in sugested_sports)
{
//
}

Related

Javascript integer to string output not matching expected values

During some basic tests of JS usage I have been playing around with object generation / addition to an array. I have so far used two different approaches for this problem:
A single global object which has fields varied and then added.
A factory function which generates the same object with an additional operation to show a slight difference (Addition of 1 to the value field)
While there are no errors at run time the value field on the global object property always outputs a 2 (Where the value is suppose to increment with the loop), while the function approach seemingly works without issue. Do you have any idea why this would be the case?
The final output I generated was "[{"name":"Hello","value":2},{"name":"Hello World","value":1},{"name":"Hello","value":2},{"name":"Hello World","value":2},{"name":"Hello","value":2},{"name":"Hello World","value":3}]" (from the console.log(JSON.stringify(testArray));).
I had expected an output of "[{"name":"Hello","value":0},{"name":"Hello World","value":1},{"name":"Hello","value":1},{"name":"Hello World","value":2},{"name":"Hello","value":2},{"name":"Hello World","value":3}]"
The code for the relevant functions and object can be found below.
Defining the global variable:
var globalVariable =
{
name: undefined,
value: undefined
}
Factory function:
function globalVariableGen(name, valueInput)
{
return output =
{
name: name,
value: valueInput + 1
}
}
Array generation function:
function test2()
{
var i, testArray = [];
for (i = 0; i < 3; i++)
{
alert(i.toString());
globalVariable.name = "Hello";
globalVariable.value = i;
testArray.push(globalVariable);
testArray.push(globalVariableGen("Hello World", i));
}
console.log(JSON.stringify(testArray));
}
Kind regards,
Shadow
This is because javascript is pass-by-reference and you're referring to the same globalVariable which you add to the array multiple times. The array then contains multiple pointers to the globalVariable which is exactly the same.
If you add a console.log(JSON.stringify(testArray) into the loop you will see this behavior.
> "[{"name":"Hello","value":0},{"name":"Hello World","value":1}]"
> "[{"name":"Hello","value":1},{"name":"Hello World","value":1},{"name":"Hello","value":1},{"name":"Hello World","value":2}]"
> "[{"name":"Hello","value":2},{"name":"Hello World","value":1},{"name":"Hello","value":2},{"name":"Hello World","value":2},{"name":"Hello","value":2},{"name":"Hello World","value":3}]"

inovke functions javascript using while

can anyone tell me what is wrong here im just try to invoke this list of functions using array and while if it's possible thanks in advance.
var funciones = ["basicas();", "likeFbk();", "cambiarFondo();"],
i = 0;
while (funciones[i]) {
funciones[i];
i++;
}
jslint show this errors:
91 Expected an assignment or function call and instead saw an expression. funciones[i];
92 Unexpected '++'.
Solved, I use "i += 1;" instead of "i++;" and update the list of functions treated as a string, here is the code:
var funciones = [basicas, likeFbk, cambiarFondo], i = 0;
while (funciones[i]) {
funciones[i]();
i += 1;
}
thank's guys!
try it this way (not sure what you intend to do though, i am guessing you want to iterate unless there is no value at ith index)
var funciones = [basicas, likeFbk, cambiarFondo], i = 0;
while (funciones[i])
{
funciones[i]();
i++;
}
You can't invoke functions like that. The functions array is just a list of strings and not a list of functions. You have two ways of doing this:
Instead of list of strings, use list of functions as below:
var functions = [basicas, likeFbk, cambiarFondo];
while (i in funciones) {
functions[i]();
}
Use eval to evaluate string that contains javascript executable code:
var funciones = ["basicas();", "likeFbk();", "cambiarFondo();"],
i = 0;
while (funciones[i]) {
eval(funciones[i]);
i++;
}
Always go for the first approach, because the second approach is considered as evil.
Or if you prefer
var call = Function.call;
[basicas, likeFbk, cambiarFondo].forEach(call, call);
How this works is left as an exercise.

JS Hint - don't make functions within a loop

I can not get around JSHint's error message. Here is the loop I am using:
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(function(item) {
return {
id: item[0],
title: item[1],
};
})
});
}
You can just move the function outside the loop and pass a reference to it to map:
function mapCallback(item) {
return {
id : item[0],
title : item[1],
};
}
for (i = 0; i < Collection.length; i += 4) {
data.push({
items: Collection.slice(i, i + 4).map(mapCallback)
});
}
Alternatively, you can use a JSHint directive to ignore function expressions inside loops. Just put this at the top of the file in question:
/*jshint loopfunc: true */
Declaring a function in a loop is messy, and potentially error prone. Instead, define the function once, and then enter the loop.
var objMaker = function(item) {
return {
id : item[0],
title : item[1],
};
};
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(objMaker)
});
}
People say "Declaring a function in a loop is messy and potentially error-prone", but functions within loops is what directly instructed in, for example, Array.prototype.forEach method. Just because the word "function" should theoretically mean defining it anew in every forEach call it does not mean it is actually defined each time by the Javascript engine.
The same goes for outer loops since engines have "lazy" processing of instructions. They are not going to redefine the whole forEach/Map/etc construct-instruction anew if nothing really changed about it, they will just feed new arguments to it.
The times of ancient JS engines which were clueless about such simple things as well as of code context are long gone. And yet we are getting this ancient warning which was conceived when functions were not yet capable of being passed as arguments as in the cases of forEach or Map.

Issue with Javascript For loop

Consider the Code below:
function splicer()
{
var arrayElements = ["elem1","elem2","elem3","elem4"];
for(var index in arrayElements)
{
arrayElements.splice(index,1);
}
alert("Elements: "+arrayElements);
}
The above function is supposed to remove all the elements from the array "arrayElements". But it won't.
Javascript engine maintains the "index" as it is and doesn't mind the array being modified.
People might expect something like "for each" loop that doesn't have this kind of issue
even the following code doesn't seem to work:
function splicer()
{
...
for(var index in arrayElements)
{
arrayElements.splice(index--,1);
}
...
}
even when changing the value of the variable "index" doesn't seem to work.
the changed value is available inside the "for(...){...}" block but, as the loop reaches the next iteration, the value gets reset and continues from the next index as clockwork.
so it seems code like this might be the only solution:
function splicer()
{
var arrayElements = ["elem1","elem2","elem3","elem4"];
for(var index=0;index<arrayElements.length;index++)
{
arrayElements.splice(index--,1);
}
alert("Elements: "+arrayElements);
}
Tested in: Firefox 16 Beta.
But placing a unary Operator inside a "splice()" method seems to be misleading at first sight.
This might be worth considering to the "W3C" or whomever it may concern so that they come up with a nice solution.
You may want to refer to John Resig's array.remove() link.
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
Try this:
*Splice modifies the original array, hence tge loop skips the alternate values. *
var arrayElements = ["elem1","elem2","elem3","elem4"];
arrayElements.splice(0,arrayElements.length);
alert("Elements: "+arrayElements)

adding chr to the number Prototype

I have the following function:
var chr = function(X) {
return String.fromCharCode(X)
}
But I would like to use i.chr() instead of chr(i).
Q: How do I add chr() to the number prototype?
Number.prototype.chr = function() {
return String.fromCharCode(this);
}
var n = 33;
console.log(n.chr());
http://jsfiddle.net/CXWeV/
Also, as Bryan points out, the following will work:
console.log((33).chr());
console.log(Number(33).chr());
But, the following does not work:
33.chr();
EDIT: Although, as Gumbo points out, this does:
33..chr();
As well as a check if the property already exists (see Erik's answer for another way to check):
if (!Number.prototype.chr) {
Number.prototype.chr = function() {
return String.fromCharCode(this);
}
}
if (!Number.prototype.hasOwnProperty('chr')) {
Number.prototype.chr = function() {
return String.fromCharCode(this);
};
}
To use this the number must be in a variable or wrapped in parentheses. Be aware that converting a scalar number to a Number object (called boxing) has an overhead. If you are doing the conversion repeatedly on the same value, you'll want to explicitly convert it to an object first with Number().
Note that simply doing String.fromCharCode might be easier or more clear in some situations.
The normal way, really. Note the importance of surrounding the number in parentheses (or storing it in a variable), as a dot would normally indicate a decimal point:
Number.prototype.chr = function () {
return String.fromCharCode(this);
}
alert((97).chr()); // alerts "a"
I'm not sure whether this works in all browsers, but I'm assuming it does.
Interactive Example

Categories

Resources