When having a simple boolean, it is simple to use it in a condition :
var running = true;
if(running) {/*do something*/}
Is there some trick to do this with a boolen array? something like this:
var running = [false,false,true,false];
if(running[]){/*do something*/}
At the moment I do it like this :
var uploading = false
for(i=0; i< running.length ; i++)
{
if(running[i]) uploading = true;
}
if(uploading)
But I feel like this is not really perfectly written code and that their could be some trick, shorthand method.. Could be plain javascript, could be Jquery
jQuery has the $.inArray method:
uploading = $.inArray(running, true) !== -1;
The name is slightly misleading, it returns the index of the element that matched (-1 if none).
JavaScript has Array#indexOf, but it's missing in IE8 and earlier:
uploading = running.indexOf(true) !== -1;
JavaScript as of ES5 has the Array#some method, but it's overkill if you can look for the specific value with either of the above. Still, it's useful if you need to massage the values at all. For instance, if any "truthy" value is okay rather than specifically true:
uploading = running.some(function(entry) { return !!entry; });
You can just use this:
uploading = running.indexOf(true) !== -1;
If the array doesn't contain a true, indexOf will return -1, resulting in a false from !== -1. If the array contains a true, indexOf will return it's index, resulting in a true.
A slightly shorter option:
uploading = !!~running.indexOf(true);
The ~ is a bitwise NOT, this inverts the value from indexOf: -1 -> 0, 0 -> -1, 1 -> -2, etc. Then the double ! first casts this value to a boolean, then inverts it again, resulting in a boolean output that's true then the array contains a true.
I just thought about little trick that can work in this situation:
uploading = !!Math.max.apply(null, [false, true, false, false]); // => true
Basically without !! path you will get 1 (if there is at least one true) or false (for all false in array). Max calls ToNumber for each passed argument, so true => 1.
Note: you'd better use indexOf, this is just for fun and to demonstrate another unobvious way.
Related
This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 4 years ago.
I'm using Javascript to find if something is in an array or not, but when I'm using this code it doesn't alert anything at all, which means it's not working correctly. What am I doing wrong?
var theArray = new Array("one","two","three");
if (theArray.indexOf("one")) { alert("Found it!"); }
if (!theArray.indexOf("four")) { alert("Did not find it!"); }
you should use the includes function as:
if (theArray.includes('one')) { alert("Found it!"); }
Remember that the starting index of an array is 0.
From the docs.
The indexOf() method returns the first index at which a given element
can be found in the array, or -1 if it is not present.
The index of one is 0, which is falsy so the first check will fail. indexOf will return -1 if there is no match so you should explicitly check for that.
var theArray = new Array("one","two","three");
if (theArray.indexOf("one") !== -1) { alert("Found it!"); }
if (theArray.indexOf("four") === -1) { alert("Did not find it!"); }
That's because indexOf returns a number which is the index of the matched string, and -1 if the string does not exist in the array. You need to compare the return value to numbers like these:
if (thisArray.indexOf('one') > -1) { alert('Found it!') }
if (thisArray.indexOf('four') > -1) { alert('Did not find it') }
You can use includes to return a boolean instead, if you'd like.
if (thisArray.includes('one')) { alert('Found it!') }
You'd think that might work, wouldn't you? But there are two gotchas here.
.indexOf() returns the index of the first matching element it finds, or -1 if it doesn't find anything. And remember that JavaScript array's are zero-indexed, meaning the first array element has the index of zero. So if the match is the first element, then zero is the returned value, and like most languages, zero means false when you'd want it to be true. However this bring us to point #2.
.indexOf() performs a comparison using strict equality, or in other words ===. The returned value won't be coerced like if you used true == 1. This is highly relevant here because if it didn't use strict equality, then any element it found (other than the first) would have an index of one or higher, and then your comparison would succeed. For example if (theArray.indexOf("two")) would work since the index of that element is 1. However, single indexOf() does a strict equality check, it fails. Which is why you need to explicitly compare the returned value of indexOf() to something, normally > -1.
Linear search. It is a 'language agnostic' approach to solving the problem of searching an unordered list. Yes, you can use array.includes(), which is a neat one-linear specific to JavaScript. But, it appears as through you are new to programming, at least with JavaScript, and before you take advantage of some of those fancy tools that make life easier, it's worth implementing them yourself so you truly understand what's going on under the hood and more importantly, why it works.
function contains(array, value) {
// Loop through the entire array
for (let i = 0; i < array.length; i++) {
// Return true on first match
if (array[i] === value)
return true
}
// Return false on no match
return false
}
// Make an array
let a = ['one', 'two', 'three']
// If it has an element, notify
if (contains(a, 'one'))
alert('found it')
You could use the bitwise NOT ~ operator and check the value of the returned index or -1 if not found.
~ is a bitwise not operator. It is perfect for use with indexOf(), because indexOf returns if found the index 0 ... n and if not -1:
value ~value boolean
-1 => 0 => false
0 => -1 => true
1 => -2 => true
2 => -3 => true
and so on
var theArray = new Array("one", "two", "three");
if (~theArray.indexOf("one")) {
console.log("Found it!");
}
if (!~theArray.indexOf("four")) {
console.log("Did not find it!");
}
I am calling two functions and checking if the given input has barcode and qr code
var decode = jsQR.decodeQRFromImage(rawImageData.data, rawImageData.width, rawImageData.height);
checkBarCode(function(err, result) {
if (result) {
Result.pages.push({
ValidTicket: decode ? true : false //here i want to assign true or false if barcode or qr code is present.
});
}
});
is this correct?
ValidTicket: decode || result ? true : false
Your assignment does work correctly, but I might suggest using two boolean NOT operators instead, which is slightly terser:
var decode = jsQR.decodeQRFromImage(
rawImageData.data,
rawImageData.width,
rawImageData.height
);
checkBarCode(function(err, result) {
if (result) {
Result.pages.push({
ValidTicket: !!(decode || result)
});
}
});
Yes, that's correct. If either decode or result is truthy*, you'll assign true; if both are falsy*, you'll assign false.
You may get someone telling you to just do this:
ValidTicket: decode || result
...but that won't necessarily assign either true or false, because of JavaScript's curiously-powerful || operator (that's a post on my anemic little blog); instead, it'll assign the value of decode if it's truthy, and the value of result if not. So if you really need true or false, you need to use the conditional as you have done.
* About "truthy" and "falsy":
"truthy" - a value that coerces to true when used as a boolean
"falsy" - a value that coerces to false when used as a boolean
The falsy values are 0, "", NaN, null, undefined, and (of course), false. All other values are truthy.
I have this:
modalTogglePreview: function ($scope) {
if ($scope.modal.wmdPreview === true) {
$scope.modal.wmdPreview = false;
} else {
$scope.modal.wmdPreview = true;
}
}
Is there some way I could achieve the same but without the if statement ?
$scope.modal.wmdPreview = !$scope.modal.wmdPreview;
The unary ! operator interprets its argument as boolean, and returns the boolean complement. Note that this really isn't exactly the same as your code: yours only works if the variable is exactly true when it's tested. In my experience (for what that's worth), relying on variables used as flags in JavaScript to be real booleans is a little fragile. (There are counter-arguments however, so it's up to you.)
To explain further, the ! operator will interpret the values undefined, null, 0, NaN, false, and the empty string "" as being false. Any other value is true.
Aside from using the not operator as Pointy mentioned (which should be the preferred way), if you find yourself setting a boolean value inside an if...else statement, then you are likely doing something wrong.
The condition is already evaluated to a boolean value. So your if...else statement is equivalent to
$scope.modal.wmdPreview = $scope.modal.wmdPreview !== true;
Have a look at these examples:
var result;
if (cond) {
result = true;
}
else {
result = false;
}
This means, if the condition (cond) is true, set result to true. If cond is false, set result to false. The value we assign to result is exactly the value of cond. Hence the above is equivalent to writing
var result = cond;
Now, sometimes we use conditions that don't evaluate to a boolean. To convert any value to its boolean equivalent, you can apply the not operator twice:
var result = !!cond;
Similar for the other way round:
var result;
if (cond) {
result = false;
}
else {
result = true;
}
If cond is true, assign false to result. If cond is false, assign true to result. This is the same as in your situation. The value we assign to result is the opposite of the value of cond. As Pointy showed, we can use the not operator for this:
var result = !cond;
This works with every condition, but depending on the expression, it can make it harder to read. For example, !(x > 5) is not as obvious as x <= 5. So if you find yourself in such a situation, you can usually flip the comparison operator.
im a JS newbie. Trying to figure out this problem below. I am stuck on the "if" statement and not sure exactly what to put in. Also im not sure if my "push" is setup right
// Define a function named `compact` that accepts an array and returns
// another array with all the falsey values removed from it. For example,
// if this array was passed in:
// [1, 4, 0, '', undefined, false, true, null, {mj: 'mj'}, 'Hello']
// the function would return this, as a result:
// [1, 4, true, {mj: 'mj'}, 'Hello']
var compact = function (array) {
var truthyValues = [];
for (var i = 0; i < array.length; i += 1) {
if () {
truthyValues.push[i];
}
}
return truthyValues;
};
You're close. Here's what the if should be:
if (array[i]) {
truthyValues.push(array[i]);
}
Since you want to check for truthiness of each array element, just put array[i] in the if block. That gets the value of the array at i, and will evaluate as true if that value is truthy.
Then push not i - the index into array - but array[i], so that the actual value is in truthyValues.
Just put the value you want to check is truthy in the if statement, since the if statement checks for truthiness.
if(array[i]){
truthyValues.push(array[i]);
}
I think you can just use:
if (array[i]) { truthyValues.push(array[i]); }
Values like null will trigger false.
if (typeof array[i] !== "undefined" && array[i] !== null) {// push to array // }
most of these other answers will not work for falsy and existy values. You'll need to define what you intend to be existy and write a helper function for that. you could use the one I provided as a start and then roll your own.
In the source code of zepto,I found that in zepto.matches function,there's a fallback perform,
zepto.matches = function(element, selector) {
if (!element || element.nodeType !== 1) return false
var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
element.oMatchesSelector || element.matchesSelector
if (matchesSelector) return matchesSelector.call(element, selector)
// fall back to performing a selector:
var match, parent = element.parentNode, temp = !parent
if (temp) (parent = tempParent).appendChild(element)
match = ~zepto.qsa(parent, selector).indexOf(element)
temp && tempParent.removeChild(element)
return match
}
despite the normal matchSelector way,I'm quite curious about the fallback,why it add ~ in front of this:
~zepto.qsa(parent, selector).indexOf(element)
document.getElementById("test");
$.zepto.matches(a,"#test") // -1
it returns -1 , is it right or am I missing something?
It's the Bitwise NOT operator. In this case it's used to have a boolean return value for indexOf: the indexOf methods (array, string), returns -1 if a match is not found, and the position if a match is found. The position can be also 0, of course. So using the bitwise NOT operator:
console.log(~-1); // 0
console.log(~0) // -1
console.log(~1) // -2
// and so on
So because in JS 0 is considered as a "Falsy" value, and any other number – except NaN – is a "Truthy" value, having ~zepto.qsa(parent, selector).indexOf(element) will returns 0 if the element is NOT found, and therefore can be thread has a "Falsy" value in the code:
var isFound = ~zepto.qsa(parent, selector).indexOf(element);
if (isFound) {
// do something
}
However, in that case I would expect the zepto methods to return a real boolean, because it's an API method. In this such case, I would prefer use simply:
match = zepto.qsa(parent, selector).indexOf(element) > -1;
Or
match = !!~zepto.qsa(parent, selector).indexOf(element);
The double ! it's used to have the proper Boolean representation: if indexOf returns -1, the ~ transform it in 0, then the first ! in true, and the second ones in false, that is the Boolean value we expect for "not found".
The Bitwise NOT it's also used for some other tricks, like this one:
var words = ["a", "b", "c", "b", "b"];
var frequency = words.reduce(function(freq, word) {
freq[word] = -~freq[word];
return freq;
}, {})
This code returns an object like {a:1, b:3, c:1}; it basically counts the frequency of the same string value in an array. Here the Bitwise NOT it's used with the Unary Negation operator to have an incremental counter: so if freq[word] is undefined – because this word is not yet in the "dictionary" – then the ~undefined is -1, and with the unary negation becames 1. The next time we'll have -~1, and therefore - -2, so 2; then -~2 will be 3 and so on.
The bitwise operators are really useful, but also easier to be abused. In some cases are necessary (For instance, the Zero-fill right shift it's currently the only way in JS to have a substitute of ToUint32) they're not, and they could lead to code hard to read.
But they're definitely worthy to be known.