"Magic" Type Conversions

To me using the unary plus operator to convert a string into a number appears obvious and yet some people seem to think that it isn't and insist on using Number() instead. Well if that one isn't obvious then there are others that are even less obvious but which can be really useful so it is worth learning them. They are only not obvious until you learn them.

To start with let's consider whether using unary plus really isn't obvious.

The issue is with the dual meanings for the plus operator when applied to two variables. Where the plus operator is used between two numbers it adds them together but f either of the two variables is a string then the alternative meaning of the plus operator is used and the two values get concatenated instead of added. The other arithmetical operators work as expected and minus, times, divide and modulo will all convert any string to a number before applying the operator.

So why isn't the unary plus operator obvious? The only thing that the operator can do is to convert the single variable it is associated with to a number. This operator doesn't do anything else at all. So if its only use is considered to be 'magic' and not obvious then those people don't really understand the purpose of the various JavaScript operators.

var num = +str;

SO having got the obvious one out of the way, let's consider a couple of not so obvious ones.

One thing that is often needed in JavaScript is to extract either the integer or the fraction part of a number separately.

Getting the fractional part is the more obvious. At least it is once you think through what the modulo operator does.

Most of the time when we are dealing with the modulo operator we are dealing with integers. I expect everyone knows that with integers we can use %2 to determine whether the integer is odd or even. Using % followed by any integer divides the original number by that integer and returns whatever part doesn't divide evenly so even numbers can be divided evenly by two and so return zero while odd numbers return the left over one and so can be easily distinguished via this operation.

The not so obvious part of this comes about because we are so used to using the % operator with integers that we overlook what happens when the number isn't an integer. Remember that it is the left over part that gets returned from the operation. So if we have 3.5%2 we'd get 1.5 returned as that is the left over part. So having realised that it should now be obvious that %1 will return the fractional part of the number as that's what's left over once you divide any number by one.

var frac = num % 1;

The really not obvious one is the one for extracting the integer part of the number.

The ~ operator is JavaScript does a bitwise NOT operation treating the value it is operating on as a binary value. All of the ones become zeros and the zeros become ones. The not obvious part until you try it is that when the variable you apply this to is a floating point number that the decimal portion of the number is discarded before the not operation is applied. ~5.4 becomes -6 the same as ~5 does.

Because the ~ operator reverses the values in each bit, running ~ again will convert them back. Doing this means that only the side effect of the first ~ of dropping the decimal portion has any effect in this situation and so using ~~ will convert any number to the integer equivalent.

var int = ~~num;

In fact to extract the integer portion any other way either relies on a side effect if a function intended for a completely different purpose (either the ~~ we have just considered or using parseInt with the second parameter set to 10) or it involves checking whether the number is positive or negative (Math.floor for positive numbers and Math.ceil for negative numbers) so even though it isn't quite as obvious as the prior two, this way is certainly the simplest (and its still as easy to follow as the alternatives provided you add a comment as a reminder of what the ~~ does).

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate