0

I am trying to understand this code from Eloquent JavaScript:

function unless(test, then) {
  if (!test) then();
}
function repeat(times, body) {
  for (var i = 0; i < times; i++) body(i);
}

repeat(3, function(n) {
  unless(n % 2, function() {
    console.log(n, "is even");
  });
});
// → 0 is even
// → 2 is even

I get that it says, run the following code 3 times testing with 0,1,2:

if (!n%2) function(n) {
  console.log(n, "is even");
});

What I don't get is how we get true/false from (!n%2)?

Is (!n%2) the same as (!n%2 == 0)?

altocumulus
  • 21,179
  • 13
  • 61
  • 84
Constantinos N
  • 253
  • 3
  • 17
  • as far as I know javascript evaluates an expression to true as long as it does not evaluate to `null` nor `undefined`. In other words, in javascript anything with a *valid/known* value evaluates to true. – Veverke Apr 12 '16 at 15:07
  • @Veverke - ...or an empty string, or `0`. – Justin Niessner Apr 12 '16 at 15:07
  • Be as explicit as possible with your conditionals. These "tricks" are language dependent, and nobody has enough time to memorize how every different language handles them. so even if (!n%2) does what you want. Don't use it. – dustinroepsch Apr 12 '16 at 15:08
  • @JustinNiessner: an empty string and 0 - does not evaluate neither to null nor undefined, so it is covered in that definition. – Veverke Apr 12 '16 at 15:08
  • 1
    truthy/falsey - See [All falsey values in JavaScript](http://stackoverflow.com/questions/19839952/all-falsey-values-in-javascript) – Alex K. Apr 12 '16 at 15:08
  • 1
    Although be careful: `!` has higher precedence than `%`. So `!n%2` is equivalent to `(!n)%2` not `!(n%2)`. – lurker Apr 12 '16 at 15:09
  • @Veverke - Wrong. Empty strings and `0` are both falsey in JavaScript. Using your definition, they should evaluate to `true`. – Justin Niessner Apr 12 '16 at 15:09
  • You've got a problem with [operator precedence](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence). You probably meant to ask whether `!(n%2)` was equivalent to `!((n%2)==0)` (*No*) or maybe `(n%2) == 0` (*Yes*) – Bergi Apr 12 '16 at 15:12
  • @JustinNiessner: you are right, thanks for that. May I ask what is the reasoning behind this behaivor ? I could find one in the definition I posed. – Veverke Apr 13 '16 at 05:55

4 Answers4

1

Logical NOT ! has higher precedence than modulo operator %.

Thus, (!n%2) is equivalent to (!n) % 2 which will always return 0 a falsy value except when n = 0.

Whereas (!n%2 == 0) will return true(again except 0).

They both are not equal, in fact they are opposite of each other(falsy vs truthy value).

You need !(n % 2).

Or simply to check if number is even

n % 2 === 0
Tushar
  • 85,780
  • 21
  • 159
  • 179
0

!Boolean(n%2) should work as a way to determine whether one is even or odd.

Remember that Boolean does not follow BIDMAS.

It does !n first where n is treated as a Boolean so that the numerical value of 0 is treated as false and any other numerical value is treated as true. The exclamation mark inverts the logic state of n.

Now the %2 converts the Boolean back to an integer where true is 1 and 0 is false. !n = 0 returns 0 and !n = 1 returns 1.

Using !n%2 in an if statement converts it back to a Boolean (1 = true, 0 = false).

Thus if n = 0 then the if statements proceeds because it returned true. If n != 0 (!= meaning not equal) then if statement is skipped because it returned false.

Bradman175
  • 168
  • 10
0

No, it's not. As stated here the "!" operator has highest precedence than "%" so the expression will return true if n is 0 and false if n is different from 0.

More in detail, suppose n is 2. the execution of the expression is:

(!n)%2
(!2)%2
0%2
0

so it is false, now for n=0

(!0)%2
1%2
1

so it is true. It is the opposite behavior of (!n%2 == 0) that returns true if n is different from 0 and false otherwise since == has less precendence and the comparison with 0 is executed at the end of the calculation above. You can easily convince yourself by using this simple javascript with different values of n:

    n = 1;
    if(!n%2)
    {
        document.getElementById("par1").innerHTML="true";
    } 
    if(!n%2 == 0)
    {
        document.getElementById("par2").innerHTML="true";
    }
JoulinRouge
  • 456
  • 4
  • 18
0

Your test code you wrote is not equivalent to the sample code from the article.

In the sample code, n % 2 is evaluated first, and the result is passed into the unless function. There, you are performing a Logical Not operation against the result.

If n is even, n % 2 will pass 0 to unless. A Boolean comparison of 0 returns false, and the ! negates the result (logical not), so !0 == true. this, in turn, causes the then function to fire.

If n is odd, the opposite occurs. Some value other than 0 is passed, which evaluates to false, causing then to not fire.

In contrast, your attempt to reproduce the sample code without using Higher-Order functions won't work the same way. !n % 2 will perform the Logical Not on n first, then try to modulo the result. !(n % 2) is a better representation of the sample code.

Claies
  • 22,124
  • 4
  • 53
  • 77
  • I see what you mean, I couldn't understand the flow in the code in the first place. I should first think in my mind what the result of `n % 2` is first and then apply the `!` on that result. This made it a lot easier to understand. – Constantinos N Apr 16 '16 at 10:43