I was reading jQuery's documentation about the inArray method and I can't really understand the meaning of one sentence. After saying that the method returns -1 if the element is not in the array, and 0 otherwise, it reads:
Because JavaScript treats 0 as loosely equal to false (i.e. 0 == false, but 0 !== false), if we're checking for the presence of value within array, we need to check if it's not equal to (or greater than) -1.
I can't understand what the fact that JavaScript treats 0 as loosely equal to false has to do with the need to check the method's return values. Would't I need to do this even if JavaScript didn't work this way?
It basically means that you need to write the test like this:
if ($.inArray(value, array) > -1) {
// the element is inside the array
}
instead of:
if ($.inArray(value, array)) {
// the element is inside the array
}
The reason why you shouldn't use the second construct is because if the value is the first element of the array the inArray function will return 0 (because that's the index of the first element of an array) and as explained in the documentation 0 means false:
if (0) {
// this will never run
}
They're just covering their backsides over the hideous mis-naming of that function1.
In other words, they're saying that you mustn't do:
if ($.inArray(a, b) == false) {
// will fail if the element is in index 0
}
1 A function named inArray would logically (no pun intended) be expected to return a boolean, not a position.
It just means inArray should have really been named indexInArray.
This makes it so that a 0 means it's been found in the first element, and not that it wasn't found.
Indexes start with 0, so 0 is a valid value in the case like
var arr = ['foo'];
console.log($.inArray('foo', arr));
So jQuery developers decided to use -1 instead of false to prevent obvious errors in case if developer checks the value presence like
if (!$.inArray(..))
In javascript 0 is false and 1 is True, or you can use true or false.
zero is a position of the array is the first item of the array.
if you compare in the if statment if(0) it is considered has false.
but your answer in the context of the array is that the item is in the zero position.
They tell you don't check for 0 is it's like false or null etc'
it will be a problem if the value is in index 0 of the array(== false)
Check if the value is greater than -1 or !=-1
Example of the problem:
if ($.inArray(20, [20]))
// won't run the value is in index - 0
if ($.inArray(20, [20]) > -1)
// Will run!
DEMO
Related
str.indexOf(searchValue[, fromIndex])
The index of the first occurrence of searchValue, or -1 if not found.
- MDN web docs
Why was -1 chosen to be the returned value by .indexOf if it doesn't find a match in the array?
console.log([].indexOf()) // -> -1
Would it not be more suitable to have 0 instead? It would make sense because there are indeed 0 matching element. And this way we could have used it directly in a conditional statement, for example:
if( Array.indexOf(String) ) { ... }
Instead of
if( Array.indexOf(String) !== -1 ) { ... }
Why is that? Any particular reason? I've seen the same in Java, C++ and C. Is this because of how the native function was designed?
Would it not be more suitable to have 0 instead?
No. Indexes start from zero.
var str = "ABC";
console.log(str[0]);
console.log(str.indexOf("A"));
(The same is true of arrays, which you used for your examples despite quoting the documentation for strings).
Well. It's pretty straight forward as to why. indexOf returns the position of an element not if it exists or not. Plus all ( 99% ) programming languages are 0 indexed, or better say strings and arrays are 0 indexed which means that the first element is at position 0.
Think of position as the offset of an element from the start of the array. So the distance/offset of the first element from the start of the array is, well, 0 :)
Maybe you are looking for includes() which checks if an element is inside an array.
const arr=[1,2,3]
// classic
if (!arr.includes(4)) {
console.log('4 does not exist (classic)')
}
// or short circuit
!arr.includes(4) && console.log('4 does not exist (short circuit)')
// conditional (ternary) operator
!arr.includes(4) ? console.log('4 does not exist (ternary)') : ""
Observation
Also you shouldn't use indexOf() as a boolean condition because for example
let arr=['a','b','c']
arr.indexOf('a') ? console.log('true') : console.log('false')
In the above example, indexOf(a) returns it's position 0. In a boolean condition 0 is treated as false by javaScript. So it would not give you the expected result.
Everyone else is saying the same thing, but let me try another wording of the answer.
In Javascript arrays are indexed starting with element 0. So if the string qas found at the begining the valid return value would be 0. If string not found was reported as 0 you would not know if it was not found or found at the beginning. -1 is never a valid value for a position in a string.
As to your test
if( Array.indexOf(String) ) { ... }
you could instead use
if( 1+Array.indexOf(String) ) { ... }
to avoid using the !== -1 test.
As a general consideration, the result of Array.indesOf() is overloaded. The result contains both the funciton result and an error code. This overloading allows the function call to be used directly in a test. Consider, however, that if the function call is in the if statement you probably will need to call the function again, which is an efficiency loss. If before the if you made an assignment of the result and then tested the result you would be computationally more efficient. There is not even a memory cost because variables in funtions are on the stack which is cleared on function return if you keep the variable local.
A function that returned a structure containing a success/fail flag and a result is a clean way to do such a thing that generalizes function calls that may fail, and is a convenient place to put exception handling without complicating the simple test you want to do.
Because in almost every programming language, 0 is the first position of an array.
indexOf() gives you the position of the element in the array and valid index of array starts from 0, 1, ... and so on till the array.length-1 so if the indexOf() would return 0 for non existence element then that would be incorrect as 0 is a valid index. Thus -1 is used.
While exiting from each loop- return 0 is not working. However, changing it to return false works perfectly.
Fiddle here
The regular JavaScript loops (while,for) exits fine by return 0. Doesn't it breaks the uniformity!
jQuery documentation
We can break the $.each() loop at a particular iteration by making the callback function return false. Returning non-false is the same as a continue statement in a for loop; it will skip immediately to the next iteration.
JSFiddle as example
The difference is simply that 0 is not the exact same thing as false.
Usually when a boolean value is required any value will be usable, and it will be converted to a boolean. In that case the 0 would be converted to false.
In a jQuery $.each loop that wouldn't work. If you don't specifically return anything from a function, then the return value is undefined. If that would be converted to a boolean that would also become false.
The $.each method doesn't convert the return value to a boolean, it specifically looks for the value false. Any other value will let the loop continue.
Simply put, 0 !== false.
In your own code, you may sometimes check for a false-like answer:
0 == false; // true
null == false; // true.
However, jQuery (rightly so) uses a strict equality (===) operator.
As such:
0 === false; // false
null === false; // false
false === false; // true
This if fundamentally an identity vs equality issue:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
To break a $.each loop, you have to return false in the loop callback.
Returning anything else skips to the next iteration, equivalent to a
continue in a normal loop.
Refer Document
Using return 0, will return zero, which is a number. Using return false says that there is nothing to return, or don't return.
I am trying to check if an array contains a given value:
var arr = [];
if (arr.indexOf(2)) {
console.log('yes');
}
Fiddle
Why is the if condition always met, although arr does not contain a value of 2? Shouldn't it return -1 and therefore nothing should be logged?
If you run this code in your browser's console, you'll see that it does return -1. However, in a JavaScript if statement, -1 is truthy so the alert will execute. As detailed in this excellent JavaScript equality table, there's only a very few values which will evaluate as false in an if statement: false, 0, "", null, undefined and NaN.
Your condition should be:
if (arr.indexOf(2) >= 0)
because in JavaScript, 0 is false when coalesced to a boolean, and any other number is considered true.
Therefore... -1 is coalesced to true.
alert(!!-1)
It does return -1 but -1 in Javascript is considered "truthy".
Try this to see that it is indeed returning -1:
var i = arr.indexOf(2);
console.log(i);
You need to explicitly compare for non-equality to -1 in your condition.
Here's an updated version of your jsfiddle:
http://jsfiddle.net/bmj8y8bj/
var a = [7,8,9,4,5,3,2,0,44];
[0,2,8].reduce(function(p,c,i,arr){return p && (a.indexOf(c)>-1) },true)
//true
[0,2,8,45].reduce(function(p,c,i,arr){return p && (a.indexOf(c)>-1) },true)
//false
[0,2,8,44].reduce(function(p,c,i,arr){return p && (a.indexOf(c)>-1) },true)
//true
Works fine!
Is it smart enough to stop when callback fn returns false the first time ?
BTW that code checks if array 'a' contains everything array 'arr' contains .
Is it smart enough to stop when callback fn returns false the first time ?
No. The return value of the callback just becomes the value of its first parameter in the next iteration.
For example, in this call:
[0,2,8,45].reduce(function(p,c,i,arr){return p && (a.indexOf(c)>-1) },true)
In each iteration, these are the values of p, c, and i (arr is always [0,2,8,45]):
p c i return
true 0 0 true
true 2 1 true
true 8 2 true
true 45 3 false
The last return value is the final return value of reduce. It will always iterate over all values in the array.
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want something that stops on the first false, use every:
[0,45,2].every(function(c,i){return a.indexOf(c)>-1 }) // false. Stops on 45
No.
The reduce() function doesn't know what your callback does; it has no idea it's always short-circuiting.
Call every() instead.
No, the reduce function invokes its callback for each value in the array. From the documentation on the reduce method:
reduce executes the callback function once for each element present in the array, excluding holes in the array, receiving four arguments: the initial value (or value from the previous callback call), the value of the current element, the current index, and the array over which iteration is occurring.
Your piece of code "seems to work" because && operator evaluates to true only when both its parameters are truthy. When you meet first false value, the accumulator value in reduce function (the first argument) becomes false, and after that there is no way to make it true again: false && <any value> is always false.
This question already exists:
What does `!!~` mean in javascript? [duplicate]
Closed 8 years ago.
I was reading this blog post which mentioned using:
!!~
I have no idea what this does? at first I thought it would give an error, but the code below does run:
var _sessions = [
"_SID_1",
"_SID_2",
"_SID_3",
"_SID_4"
];
if(!!~_sessions.indexOf("_SID_5")) {
console.log('found');
} else {
console.log('!found');
}
output:
node test.js
!found
~ is the bitwise not operator. It inverts the bits of its operand. ! is the logical not operator. The bitwise not operator will return 0 when applied to -1, which is what indexOf returns when the value is not found in the array. Since 0 evaluates to false, doubly negating it will simply return false (a boolean value, rather than a numeric one):
var index = _sessions.indexOf("_SID_5");
console.log(~index); // 0
console.log(!~index); // true
console.log(!!~index); //false
The bitwise not operator will return a value less than 0 for any other possible value returned by indexOf. Since any other value will evaluate to true, it's just a shorthand method (kind of... they are both the same number of characters!) of checking whether an element exists in an array, rather than explicitly comparing with -1:
if (_sessions.indexOf("_SID_5") > -1) {
// This would work the same way
}
Update
With regards to the performance of this, it appears (in Chrome at least) to be marginally slower than the more common comparison with -1 (which itself is marginally slower than a comparison with 0).
Here's a test case and here's the results:
Update 2
In fact, the code in your question can be shortened, which may have been what the author was attempting to do. You can simply remove the !!, since the ~ will always result in 0 or below (and 0 is the only value that will evaluate to false):
if (~_sessions.indexOf("_SID_5")) {
// This works too
}
However, in a slightly different situation it could make sense to add in the ! operators. If you were to store the result of the bitwise operator in a variable, it would be a numeric value. By applying the logical not operator, you get a boolean value (and applying it again ensures you get the correct boolean value). If for some reason you require a boolean value over a numeric one, it makes a little bit more sense (but you can still just use the normal comparison with -1 or 0):
var inArray = !!~_sessions.indexOf("_SID_5");
console.log(typeof inArray); // boolean
Donald Knuth: "[...] premature optimization is the root of all evil"
For the sake of readability: please use
.indexOf !== -1
This explains it well:
The tilde operator in Javascript
Mixing the two NOT operators together can produce some interesting results:
!~(-2) = false
!~(-1) = true
!~(0) = false
!~(1) = false
!~(2) = false
So this just checks if the value equals -1 or not, and indexOf returns -1 if it does not find a match