Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: 0 represents true in some cases?

Tags:

javascript

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?

like image 324
Randy Avatar asked Dec 07 '25 07:12

Randy


2 Answers

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());
like image 122
T.J. Crowder Avatar answered Dec 09 '25 19:12

T.J. Crowder


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'.
like image 37
Aditya Singh Avatar answered Dec 09 '25 19:12

Aditya Singh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!