1

I'm attempting to compare two arrays using the jQuery's .inArray. This seems straightforward but each value that is compared comes back as -1 (not in the array). Below is my code

finalClick(); function finalClick(){ roles=["President", "Dog", "Treasurer"] neededRoles=["President", "Secretary", "Treasurer"]; $(neededRoles).each(function(){ if(jQuery.inArray(this, roles)=='-1'){ console.log("not in array "+this); } }); } 

If you want to play around with it, you can check out my fiddle here.

Thanks in advance

3
  • @Bergi Strict mode can be avoided in favour of modern methods: neededRoles.forEach(role) { if( roles.indexOf(role) < 0) console.log("Not in array: "+role); } ;) Commented Jun 19, 2015 at 8:51
  • @NiettheDarkAbsol: It can, but strict mode is a Good Thing(tm). :-) Commented Jun 19, 2015 at 9:00
  • @NiettheDarkAbsol: Wait, you dare not to use jQuery at all?! :-) Commented Jun 19, 2015 at 9:14

2 Answers 2

6

In loose mode, this is always an object type, not a primitive type. So the this in your callback is a String, not a primitive string. inArray uses === (strict equality) for the check, and a primitive string is not strictly equal to a String object.

Several options for you:

Use strict mode

In strict mode, this can be a primitive, and so your code works (if I add variable declarations; see the "side note" at the end of the answer):

"use strict"; var consoleLine = "<p class=\"console-line\"></p>"; console = { log: function (text) { $("#console-log").append($(consoleLine).html(text)); } }; finalClick(); function finalClick(){ var roles=["President", "Dog", "Treasurer"] var neededRoles=["President", "Secretary", "Treasurer"]; // console.log("test: "+roles[0]); var rolecount=0; console.log("value changed"); $(neededRoles).each(function(){ //console.log("this is this "+this+" "+rolecount+" "+roles[rolecount]); if(jQuery.inArray(this, roles)=='-1'){ console.log("Not in array "+this); } else { console.log("Found in array "+this); } //rolecount++; }); }
<div id="console-log"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Use $.each instead of $().each

Instead of $(neededRoles).each(...), use $.each(neededRoles, function(index, role) and use role, which will be a string primitive:

var consoleLine = "<p class=\"console-line\"></p>"; var console = { log: function (text) { $("#console-log").append($(consoleLine).html(text)); } }; finalClick(); function finalClick(){ var roles=["President", "Dog", "Treasurer"] var neededRoles=["President", "Secretary", "Treasurer"]; // console.log("test: "+roles[0]); var rolecount=0; console.log("value changed"); $.each(neededRoles, function(index, role){ //console.log("this is this "+this+" "+rolecount+" "+roles[rolecount]); if(jQuery.inArray(role, roles) == -1){ console.log("Not in array " + role); } else { console.log("Found in array " + role); } //rolecount++; }); }
<div id="console-log"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Use Array#forEach and Array#indexOf

Or better yet, use Array#forEach and Array#indexOf, shimming them on really old browsers that don't have them:

var consoleLine = "<p class=\"console-line\"></p>"; var console = { log: function (text) { $("#console-log").append($(consoleLine).html(text)); } }; finalClick(); function finalClick(){ var roles=["President", "Dog", "Treasurer"] var neededRoles=["President", "Secretary", "Treasurer"]; // console.log("test: "+roles[0]); var rolecount=0; console.log("value changed"); neededRoles.forEach(function(role) { if (roles.indexOf(role) == -1) { console.log("Not in array " + role); } else { console.log("Found in array " + role); } //rolecount++; }); }
<div id="console-log"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Use Array#filter

If your goal is to find missing roles that are required, you can use Array#filter:

var consoleLine = "<p class=\"console-line\"></p>"; var console = { log: function(text) { $("#console-log").append($(consoleLine).html(text)); } }; finalClick(); function finalClick() { var roles = ["President", "Dog", "Treasurer"] var neededRoles = ["President", "Secretary", "Treasurer"]; var missingRoles = neededRoles.filter(function(role) { return roles.indexOf(role) == -1; }); console.log("Missing roles: " + missingRoles.join(", ")); }
<div id="console-log"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


Side note: Your original code was falling prey to The Horror of Implicit Globals because you weren't declaring a lot of your variables. I've fixed that in all of the above examples.

Sign up to request clarification or add additional context in comments.

4 Comments

+1 for the thorough explanation - the difference between primitives and wrapper objects is easily forgotten.
You could also just change this to this.toString()? jsfiddle.net/ctn2zv5n
@JamieBarker: Hah! Yes, you could. :-)
@JamieBarker Or ""+this but do you really want to throw another "hack" into the mix?
3

The jQuery each method has 2 parameters: index and element. If you use these parameters instead of this your code works

var consoleLine = "<p class=\"console-line\"></p>"; console = { log: function (text) { $("#console-log").append($(consoleLine).html(text)); } }; finalClick(); function finalClick() { roles = ["President", "Dog", "Treasurer"] neededRoles = ["President", "Secretary", "Treasurer"]; // console.log("test: "+roles[0]); rolecount = 0; console.log("value changed"); $(neededRoles).each(function (i, e) { // using index and element if (jQuery.inArray(e, roles) == '-1') { console.log("not in array " + e); } }); } 

jQuery doc for each method

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.