I was checking the JS spec, and ran into this strange behaviour:
Say you have an array of animals.
Say you want one number to represent the animals you have, to save memory.
That number actually represents the binary value of the number, which can be used to convert to an array of Booleans.
converting that number to its binary value, you have to split it into an array and pop the value every time, because you don't have leading 0's.
Okay that sounds vague, so lets put an example in position:
var pets = ['cat', 'dog', 'salamander', 'fish', 'lion', 'ape'];
var iHavePets = parseInt(1001, 2); // 9
// we can't have leading 0's, so read this right to left.
// this actually represents 001001
var petBools = iHavePets.toString(2).split("");
console.log(petBools);
while(pets.length > 0){
// petBools == [1, 0, 0, 1]
// popping it would represent: 1, 0, 0, 1, undefined, undefined
console.log(petBools.pop() ? !!pets.pop() : !pets.pop());
}
// remember we pop(), so read right to left in the array's.
// here I expect the following:
// We start with a 1
// so pets.pop() should push true
// then we have a 0
// so !pets.pop() should push false.
// however: the 0 is actually true in this case, causing it to push 'true'.
The same example by hand DOES work:
var fish = ['salmon', 'tuna', 'shark'];
console.log(1 ? !!fish.pop() : !fish.pop()); // true
console.log(0 ? !!fish.pop() : !fish.pop()); // false
console.log(undefined ? !!fish.pop() : !fish.pop()); // false
Could someone explain to me why JS is behaving this weird?
JavaScript: 0 represents true in some cases?
No, the value 0 is never truthy. The value "0" is truthy (a string containing the digit 0), but the value 0 is not. The fact that "0" (the string) is truthy is why your first example behaves the way it does.
If you want your loop to show the results you expect, coerce the string to number:
console.log(+petBools.pop() ? !!pets.pop() : !pets.pop());
// ---------^
or convert rather than coerce (just changes the rules slightly, no difference for "0" or "1"):
console.log(parseInt(petBools.pop()) ? !!pets.pop() : !pets.pop());
// ---------^^^^^^^^
why JS is behaving this weird?
Because pop is a mutating operation. If you use the same array for all the operations, you'll get consistent results:
var fish;
fish = ['salmon', 'tuna', 'shark'];
console.log(1 ? !!fish.pop() : !fish.pop());
fish = ['salmon', 'tuna', 'shark'];
console.log(0 ? !!fish.pop() : !fish.pop());
fish = ['salmon', 'tuna', 'shark'];
console.log(undefined ? !!fish.pop() : !fish.pop());
That is because '0' in your case is string 0 and not the number 0
If you change the 0 to number 0 you will have the expected behaviour of false
var pets = ['cat', 'dog', 'salamander', 'fish', 'lion', 'ape'];
var iHavePets = parseInt(1001, 2);
// we can't have leading 0's, so read this right to left.
// this actually represents 001001
var petBools = iHavePets.toString(2).split("");
console.log(petBools);
while(pets.length > 0){
// petBools == [1, 0, 0, 1]
//console.log(petBools);
var poppedValue = parseInt(petBools.pop(), 10)
// popping it would represent: 1, 0, 0, 1, undefined, undefined
console.log(poppedValue ? !!pets.pop() : !pets.pop());
}
// remember we pop(), so read right to left in the array's.
// here I expect the following:
// We start with a 1
// so pets.pop() should push true
// then we have a 0
// so !pets.pop() should push false.
// however: the 0 is actually true in this case, causing it to push 'true'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With