This question already has answers here:
Array.prototype.includes vs. Array.prototype.indexOf
(11 answers)
Closed 5 years ago.
We have list of ids i.e.1,2,3.
There is a function which accepts id and returns if passed id is in this list or not:
function isIdInList(id) {
return [1,2,3].includes(id);
}
OR
function isIdInList(id) {
return [1,2,3].indexOf(id) > -1;
}
i.e. isIdInList(1) returns true.
isIdInList(5) returns false.
What is the best solution to this, 1 of above two or any other? (Considering the list is hardcoded & The solution should be compatible for all browsers.)
Array.prototype.includes comes from ES2016 specification. It is not supported very well in all web browsers (especially if they are not up-to-date...), so you should probably use the solution with indexOf for full compatibility.
Of course, if you compile your code with Babel or Traceur, you can use includes but it would be wise to add a polyfill like the one suggested in MDN documentation:
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, 'includes', {
value: function(searchElement, fromIndex) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If len is 0, return false.
if (len === 0) {
return false;
}
// 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
var n = fromIndex | 0;
// 5. If n ≥ 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
function sameValueZero(x, y) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
}
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(searchElement, elementK) is true, return true.
// c. Increase k by 1.
if (sameValueZero(o[k], searchElement)) {
return true;
}
k++;
}
// 8. Return false
return false;
}
});
}
Related
When reading source of D3.js I saw x >= x pattern. If it is for detecting NaNs among numbers, why not just isNaN(x) or x == x?
Source, where I encountered it:
d3.min = function(array, f) {
var i = -1, n = array.length, a, b;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
}
return a;
};
From my investigations, d3.min is supposed to work on any kind of orderable values, not only numbers. isNaN would only work numbers.
d3 was actually using == at some point. This commit introduced the x == x test:
Unlike Math.min and Math.max, it doesn't make sense to return negative or positive infinity for d3.min and d3.max; the D3 functions return the minimum value according to an arbitrary ordering, not by numeric value. Instead, the minimum or maximum of an empty array, or an array that contains only degenerate values, should always be undefined.
This commit changed x == x to x <= x (which was later again changed to x >= x):
In addition to NaN, which is not equal to itself, you can have objects that are not orderable due to defined valueOf functions which return NaN. For example:
var o = new Number(NaN);
Here, o == o is true, but o <= o is false. Therefore it was possible for d3.min, d3.max and d3.extent to observe these non-orderable values rather than ignore them as intended. The fix is to check !(o <= o) rather than o == o.
OK, I see that x >= x gives false for both NaN and undefined. (Unlike isNaN(x) or x == x.)
EDIT: While it is one of the use cases of x >= x, in this case (thx #Felix Kling for pointing this out) undefined is already being checked.
This question already has answers here:
Determine whether an array contains a value [duplicate]
(18 answers)
How to check if jQuery object exist in array?
(5 answers)
Closed 9 years ago.
I have to check whether a variable is equal to a given number or another. For example I am doing this right now.
if (num == 1 || num == 3 || num == 4 || etc.) {
// Do something
} else if (num == 2 || num == 7 || num == 11 || etc.) {
// Do something
}
I thought there should be an easier way. for example an array of all numbers per if statement.
var array1 = [1,3,4,5,6,8,9,10 etc.]
var array2 = [2,7,11,12,13,14 etc.]
And then see if the number is equal to anything inside one of these arrays. But I don't know how to do it..
The indexOf() method searches the array for the specified item, and returns its position.
var array1 = [1,3,4,5,6,8,9,10];
var a = array1.indexOf(46); //a = -1; if not found
If you need to support environments that don't have .indexOf(), you could implement the MDN fix.
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this === void 0 || this === null) throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) return -1;
var n = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n !== n) // shortcut for verifying if it's NaN
n = 0;
else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
if (n >= len) return -1;
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) return k;
}
return -1;
};
}
Since you're asking for jQuery, there is .inArray(). This returns a -1 if it isn't found, else the index of the matching element.
why dont you do a simple for loop?
for(var i = 0; i < array1.length; i++)
{
if(array[i] == num)
{
// do something
break;
}
}
You might use inArray function (http://api.jquery.com/jQuery.inArray/)
<script>var arr = [ 4, "Pete", 8, "John" ];
var $spans = $("span");
$spans.eq(0).text(jQuery.inArray("John", arr));
$spans.eq(1).text(jQuery.inArray(4, arr));
$spans.eq(2).text(jQuery.inArray("Karl", arr));
$spans.eq(3).text(jQuery.inArray("Pete", arr, 2));
</script>
Output:
"John" found at 3
4 found at 0
"Karl" not found, so -1
"Pete" is in the array, but not at or after index 2, so -1
You can do it without jQuery:
if(array1.indexOf(num1) >= 0)//if -1, then not found
You don't need to use jQuery. This is a built in function called indexOf:
if ( arr.indexOf(item) !== -1 ) {
// item is in array
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
IE9 array does not support indexOf
My Code:
var arrFruits = ['apple', 'banana', 'carrot', 'dates'];
var position = arrFruits.indexOf( 'carrot' );
position > -1 && arrFruits.splice( position, 1 );
alert( arrFruits );
The above code is displaying the result as apple, banana, dates in Chrome. But it is not working in IE9.
It may be issue of .indexOf not being supported. It basically is supported in IE9 unless some malicious doctype is triggering it to render page in IE7/8 mode. Than Array.indexOf method is not supported.
I suggest using HTML5 doctype for example (<!DOCTYPE html>) to make sure IE9 is rendering correctly.
till IE8 it doesn't have .indexOf method , you can add it like this, if you are using IE9 check for compatibility mode
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
What is this line for
position > -1 && arrFruits.splice( position, 1 );
It evaluateto either true or false and then you don't do anything with it.that's probably causing a syntax error in IE, which the more forgiving Javascript engines on chrome and Firefox are ignoring.
Maybe you meant to make an if statement?
if(position > -1) {
arrFruits.splice( position, 1 );
}
In Fabric.js you see a lot of places where a code block enclosed in a condition check of format:
if (!Array.prototype.indexOf) {} or
if (!Array.prototype.forEach) {} etc.
Isn't the result always false? Why checking the boolean value of a method?
Thanks.
Those tests pass when the functions aren't defined.
Old browsers don't have those functions. That's why they're testing for their presence.
The MDN gives the same example (classical) of this test used to define a replacement function for array.indexOf (for IE before version 9) :
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
It is checking for the existence of the method. If it doesn't exist, it will be undefined, so it'll be doing !undefined, resulting in true.
I would assume that the code is introducing a shim if it doesn't exist.
I wasn't aware of the bad crossbrowser compatibility of array.indexOf() . But now that I am, I need to find a way to achieve the same thing but without using the previous method.
I tried googling for a while, but found no real convincing answers. For now, I am doing it with loops (but this is slow and I am sure there are better ways)
Side Notes:
I can't use jQuery or any other libraries/frameworks.
It doesn't necessarily need to return the index (a simply true/false
will be ok)
I thought it is not necessary to share my code, since you all know how array-loop check looks like (plus it will lower your IQ)
Here is how inArray is implemented in jQuery:
function inArray(elem, array, i) {
var len;
if ( array ) {
if ( array.indexOf ) {
return array.indexOf.call( array, elem, i );
}
len = array.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
for ( ; i < len; i++ ) {
// Skip accessing in sparse arrays
if ( i in array && array[ i ] === elem ) {
return i;
}
}
}
return -1;
}
You can not use jQuery but why not use their implementation? :-)
Best regards!
From MDN:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
This checks if it sees a native implementation, if not implement it.
Notable Quirks:
t.length >>> 0; is an unsigned shift for force this to a positive number
For now, I am doing it with loops (but this is slow and I am sure there are better ways)
No matter what you do, it will at the end of the day involve loops. Unless you invent a O(1) algorithm for searching inside an array. There is nothing wrong with using a loop to find the corresponding element. You could even extend the built-in array object with this method so that you can reuse it.