# Friday, November 30, 2007

## A Practical Guide To Numbers in JavaScript

### Dealing with numbers, strings and JavaScript can be frustrating for a beginner. This is a down-and-dirty explanation of converting strings to numbers, detecting if a string is a number, and handy functions for manipulating numbers.

How many times have you gotten a number from a FORM field on your web page, tried to add it to a number only to get the wrong value back!? One of the most basic tasks of any program is converting between different data types. JavaScript is pretty flexible, but there are still some rules.

In most programming languages, a number is a primitive data type, meaning it's just a value stored in memory. In JavaScript, a number is both a primitive data type and a whole class of data and functions. Whether or not a primitive number or object-oriented number is used depends on how you are using it. A few quick examples are in order.

#### Creating Number Variables in JavaScript

```var num1 = new Number("4");
var num2 = 4;```

There are two basic ways of declaring number variables in JavaScript: By calling the `Number` class constructor directly using the `new` command, and by simply assigning a number to a variable. The most effecient method is by simply assigning a number to a variable, as this creates a primitive value number. The `new Number()` method creates an instance of the `Number` class and adds functions and properties to the number variable. The browser will try converting any data passed to the `Number()` function into a number, and if you're not carefull you'll get a `NaN` value, which means the value is Not A Number.

Once you have a number variable declared, you'll want to do some math. JavaScript gives us the basic mathematical operators, like +, -, * and / for add, subtract, multiply and divide. Below is a list of some of the mathematical operators in JavaScript:

Common JavaScript Mathematical Operators
Operator Name Description
`+` Addition The sum of two numbers.
++ Increment Increase the number by 1: `num1++;`
`+=` Add-to Add a number to the current value: `num += 2;`
`-` Subtraction The difference between two numbers.
`--` Decrement Decrease the number by 1: `num1--;`
`-=` Subtract-from Subtract from the current value: `num1 -= 2;`
`*` Multiplication The multiplication of two numbers
`/` Division Division of two numbers
`%` Modulus Returns the remainder of the division of two numbers

All the operators work as expected except for the addition operator. In JavaScript, the `+` operator returns the sum of two numbers, or joins two strings together. The following code example illustrates when the browser knows whether to join a string or perform a mathematical operation:

#### Using `+` to join two strings, or add two numbers

```var sum1 = 5 + 2;
var sum2 = 5 + "2";

alert(sum1); // Shows the number 7
alert(sum2); // Shows the string "52"```

When you add a string to a number, the browser automatically converts the number to a string, and then joins the two strings. The operation `5 + "2"` is interpretted by the browser as `"5" + "2"`, joining the two strings together and converting the end result into a string. This is an easy way to convert a number to a string, but is little help for converting a string to a number.

In most programming languages, you have two basic types of numbers: Integers, which represent whole numbers like 1, 8 or -3; and floating point numbers like 33.8 and -6.5. JavaScript uses floating point numbers with up to 16 decimal places.

While the addition operator adds two numbers or joins two strings, the subtraction operator only subtracts two numbers. The browser also makes your life easier by automatically converting data types:

```var diff1 = 5 - 2;
var diff2 = "5" - 2;

alert(diff1) // Shows the number 3
alert(diff2) // Shows the number 3```

When you try subtracting a number from a string, the browser automatically converts the string to a number, and then performs the mathematical operation.We've seen how mathematical operators can convert between strings and numbers, but you aren't limited to those methods. There are many more which can be used for different reasons.

#### Converting Strings to Numbers

There are four main ways to convert a string to a number: The `parseFloat`, `parseInt` and `Number` functions, and subtracting a number from a string. First, let's revisit the `Number()` function.

Earlier we learned the `Number()` function takes a value and converts it to a number, and is also the class constructor used for all number variables in JavaScript. It seems like the obvious choice, but let's take a closer look.

```var num1 = Number("2.25");
var num2 = Number("Price: \$2.25");
var num3 = Number("three");
var num4 = Number("200.8 dollars");

alert(num1); // Shows the number 2.25
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN
alert(num4); // Shows NaN```

Right away we can see a problem. The `Number()` function successfully converts a string to a number only as long as the string only contains numeric characters (those being 0 through 9, the decimal point or period, and the negative sign or minus). If there are any other characters, the `Number` function returns a `NaN` value, which literally means "Not A Number." If we have full control of what gets put in a string variable, the `Number()` function may be the right choice, but if you are taking input from the user, we may get non-numeric characters. We need a way to remove non-numeric characters from a string, then convert them to a number.

##### Cleaning and converting strings to numbers using the `parseFloat()` and `parseInt()` functions

JavaScript gives us two built in functions that help remove non-numeric characters from a string. The `parseFloat` function returns a floating point number, or decimal number, and the `parseInt` function returns an integer number. Later on we'll see why special care must be taken with the `parseInt` function.

###### Using parseFloat
```var num1 = parseFloat("2.25");
var num2 = parseFloat("Price: \$2.25");
var num3 = parseFloat("three");
var num4 = parseFloat("200.8 million dollars");

alert(num1); // Shows the number 2.25
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN (Not A Number)
alert(num4); // Shows the number 200.8```

We run into a similar problem with `parseFloat` that we have with the `Number` function. If the string contains non-numeric characters before the numeric characters, a `NaN` value is returned. It does, however, remove non-numeric characters after the numeric characters, and returns a floating point number. Likewise, if only numeric characters are in the string, a floating point number is returned. Lastly, if no numeric characters exist in the string, a `NaN` value is returned.

###### Using parseInt
```var num1 = parseInt("2.25");
var num2 = parseInt("Price: \$2.25");
var num3 = parseInt("three");
var num4 = parseInt("200.8 million dollars");
var num5 = parseInt("0x10");

alert(num1); // Shows the number 2
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN (Not A Number)
alert(num4); // Shows the number 200
alert(num5); // Shows the number 16```

The `parseInt` function works exactly the same as the `parseFloat` function, with two notable differences: It returns a number rounded down to the next integer, and it doesn't always return `NaN` when you give it non-numeric characters. In fact, it appears quite confusing. Giving `parseInt` the string "0x10" returns the number 16 ... um ... what? Sixteen? Giving it the characters zero-x-one-zero is equal to the number 16? Yes. The `parseInt` function takes up to two parameters: The string to convert to a number, and an optional second parameter specifying the number system the string should be interpretted as, called the radix. When using `parseInt`, always pass 10 as the second parameter, meaning the `parseInt` function should interpret the string as a base 10 number. A base 10 number uses the numerals 0 through 9, and every tenth value is put at a new decimal spot. We don't have a number to represent the number ten, instead we use 10: We have one group of ten, and zero groups of one.

When the string passed to the `parseInt` function begins with "0x" and no second parameter is given, the `parseInt` function treats the string like a base 16, or hexadecimal number. The hexadecimal number 10 is equal to the decimal number 16. In hex, you have one group of 16, and zero groups of 1. The equivalent number in the decimal or base 10 system is 16: one group of ten, and 6 groups of one.

###### The proper way to use parseInt
```var num1 = parseInt("2.25", 10);
var num4 = parseInt("0x10", 10);

alert(num1); // Shows the number 2
alert(num2); // Shows NaN (Not A Number)```

In the example above, the `parseInt` function is told that the string should be treated as a base 10 number, and thus "0x10" is Not A Number (`NaN`). Since humans use the decimal system when counting, you should always pass 10 as the second parameter to the `parseInt` function. If 10 is not passed as the second parameter and a user accidentally types in 0x15 instead of 0.15, you would get 21 instead of the number zero, and your calculations will be incorrect.

Number, parseFloat and parseInt Summary
Function Parameters Return Value
Number String[required] Number or NaN if the string contains non-numeric characters.
parseFloat String[required] Number or NaN if the string contains non-numeric characters.
parseInt String[required], Number[optional] The first parameter is a string, and the second parameter is a number. The second parameter is optional, and is the number system the string should be interpretted as. Use 10 unless you want a different number system. An integer rounded down to the nearest number is returned, or NaN if any non-numeric characters are found.
##### toNumber(): Clean strings and convert them to numbers

The `parseFloat` and `parseInt` functions still don't allow us to remove all non numeric characters. Unfortunately, JavaScript doesn't have a function for this, so we'll build one. You can probably search the Internet for something similar, and many times it is named toNumeric or toNumber.

###### Function definition for toNumber
```/**
* toNumber  Converts a string to a number
*
* @param   string (required)   String to convert to a number
* @param   bool   (optional)   Make it an integer and drop decimal
* @param   bool   (optional)   Round number up or down to nearest int?
* @return  float, int or NaN   Number, or null if string not a number
*/
function toNumber(str, isInteger, roundNum) {
var num;
var strType = typeof(str);

if (strType == "string") {
// Strip non-numeric chars and convert to number
num = Number(str.replace(/[^0-9-.]/g, ""));
} else if (strType != "number") {
// Return NaN if not a number
return NaN;
}

if (isNaN(num)) {
return NaN;
} else if (isInteger) {
return Math.floor(num);
} else if (roundNum) {
return Math.round(num);
} else {
return num;
}

}```

The `toNumber` function removes non-numeric characters from a string, and also allows you to specify whether or not the number is a floating point number or integer, and if it should be rounded to the nearest integer instead of dropping the decimal all together. If the string passed to the `toNumber` function contains no numeric characters, a null value is returned. Let's see how we can use this function:

###### How the toNumber function reacts to various input
```var num1 = toNumber("2.25");
var num2 = toNumber("Price: \$2.25");
var num3 = toNumber("200.8 million dollars");
var num4 = toNumber("103.8", true);
var num5 = toNumber("103.8", true, true);
var num6 = toNumber("no numbers here");

alert(num1); // Shows the number 2.25
alert(num2); // Shows the number 2.25
alert(num3); // Shows the number 200.8
alert(num4); // Shows the number 103
alert(num5); // Shows the number 104
alert(num6); // Shows null```

As mention earlier, users can type whatever they want into form fields, so you must clean the data before you can do any math with it. The `toNumber` function does several things:

1. If a number variable is given, the number is returned as a floating point, integer or rounded floating point number.
2. Removes all non-numeric characters from the string, both before and after the number characters.
3. You can specify if the number is an integer, and also if it should be rounded up or down to the nearest integer
4. If the string variable given does not contain numeric characters, a NaN value is returned. You can outright test for a NaN value if you want to tell the user to enter a number.

Let's create a sample script that shows how to use this function.

##### Using toNumber to check for user errors
```// Ask the user to enter a number
var userNum = prompt("Type a number:");

// Convert what the user typed into a number
var num = toNumber(userNum);

if (isNaN(num)) {
// Error: User typed no numeric characters
alert("Only numeric characters are allowed");
} else {
// User typed at least one number, now show the sum
num = num + 8;
alert("The sum is " + num);
}```

This shows the basic process for taking data from the user, cleaning it, and detecting possible errors.

1. The variable `userNum` is gotten from the user by way of the `prompt` function. The `prompt` function returns a string of what the user typed into the `prompt` pop up box.
2. We pass the `userNum` variable to the `toNumber` function.
3. The `toNumber` function returns a value, and is assigned to the `num` variable.
4. If the `num` variable is equal to null, then the user didn't type in any numeric characters. Show an error message.
5. Otherwise, the `num` variable is a number, and we can show the sum.
###### Drawbacks to the toNumber() function

At first this function seems like a great idea — remove all non-numeric characters from the string, and then convert it to a number. What if the user accidentally types "5/8" when they meant to type in "5.8"? The `toNumber` function would return the number 58, which is vastly larger than the 5.8 the user intended on entering. It's up to you as the programmer to decide if this fault tolerance is acceptable in your script. While posting on WebDeveloper forums, I got involved in a discussion about converting strings to numbers. In order to reduce the impact of user errors on your script, the following basic algorithm is recommended when converting strings to numbers:

1. Convert the string to a number first. Use the `Number()` function.
2. Test the converted number to ensure it is actually a number using the `isNaN()` function.
3. If the number is Not A Number, alert the user to his or her error and stop processing.
4. If the number is a number, then continue processing.
##### Using isNaN() to detect non-numbers

The function definition for `toNumber` introduced us to a new number-related function: `isNaN`. The `isNaN` function stands for "IS Not A Number" and is a native function to JavaScript. It takes a string or number as a parameter and will return true if any non-numeric characters are found in the case of a string, or if the number passed is a `NaN` value. In addition, if you were to use the `Number`, `parseFloat` or `parseInt` functions to convert a string to a number, and a `NaN` value is returned by any of those functions, `isNaN` will return true.

The `isNaN` function is complimentary to `parseFloat` and `parseInt`, and is a direct compliment to `Number`. When the `Number` function returns an actual number, the `isNaN` function returns false. When the `Number` function returns a `NaN` value, the `isNaN` function returns true. Be aware that there are times when a string passed to `isNaN` will return true, meaning the string is not a number, when that same string passed to either `parseFloat` or `parseInt` will return a number. Always convert strings to numbers first, then test using `isNaN`.

###### How isNaN reacts to various input
```var num1 = isNaN("2.25");
var num2 = isNaN("Price: \$2.25");
var num3 = isNaN("three");
var num4 = isNaN("200.8 million dollars");
var num5 = parseFloat("no numbers"); // Returns NaN value

alert(num1); // Shows false
alert(num2); // Shows true
alert(num3); // Shows true
alert(num4); // Shows true
alert(isNaN(num5)); // Shows true```

If you don't want to use the `toNumber` function above, use the `Number` function to convert a string to a number, then use the `isNaN` function to check for a `NaN` value.

###### Using isNaN to check for user errors
```var userNum = prompt("Enter a number:");
var num = Number(userNum);

if (isNaN(num)) {
alert("Only enter numeric characters.");
} else {
num = num + 8;
alert("The sum is " + num);
}```

We've learned several ways to convert strings to numbers and account for user errors. We know that `parseFloat` gives us a floating point number, and `parseInt` gives us an integer, but `parseInt` drops the decimal all together. The number 8.9 becomes 8, when it should be 9 when rounded to an integer. We need a way to create a rounded integer, and the `Math` object provides us with a `round` function.

##### Rounding numbers properly using Math.round

Any floating point number whose decimal is less than .5 must be rounded down. If the decimal is .5 or greater, the number should be rounded up. This was something we learned in grade school, but the `parseInt` function failed that class. It just drops the decimal place all together. Let's use `Math.round` instead.

```var num1 = Math.round(3.75);
var num2 = Math.round(3.33);

alert(num1); // Shows the number 4
alert(num2); // Shows the number 3```

Since the decimal in 3.75 is greater-than or equal-to .5, the `Math.round` function returns the integer number 4. The number 3.33 has a decimal less than .5, so the `Math.round` function returns the integer number 3. `Math.round` only returns integers, however. If you want to round a number to a certain decimal place, we've got to use a native function to all `Number` variables in JavaScript, which we will use in our next example.

##### A simple form to calculate the tax

We've explored several methods of converting strings to numbers, and dealing with invalid data. Now let's create a practical example using the methods outlined above, and introduce one more method for formatting the display of numbers. First, let's create our HTML form:

###### Markup for our tax form
```<form method="get" action="" id="frmTax">
Price: <input type="text" name="price" value="">
<br>
Tax Rate: <input type="text" name="taxRate" value="0.06">
<br>
<input type="button" value="Calculate Tax"
onclick="calcTax(this.form)">
</form>```

It's a pretty simple form. Before some of you scream, "It's not accessible! Burn in Hell!" know that this is just a simple example. Web accessibility is beyond the scope of this tutorial. We've got two text fields: One for the price, and another for the tax rate. Lastly, we have a button that calls the calcTax function onclick, and passes a Document Object Model node reference to the FORM tag.

###### Example 1: Function definition for calcTax, using toNumber()
```function calcTax(form) {
var price = toNumber(form.elements["price"].value);
var taxRate = toNumber(form.elements["taxRate"].value);
var total = 0;

if (isNaN(price)) {
alert("Only enter numeric characters for the price");
return;
} else if (isNaN(taxRate)) {
alert("Only enter numeric characters for the tax rate");
return;
} else {
total = price + (price * taxRate);
alert("The total price is: \$" + total.toFixed(2));
}
}```
###### Example 2: Function definition for calcTax, using native functions
```function calcTax(form) {
var price = Number(form.elements["price"].value);
var taxRate = Number(form.elements["taxRate"].value);
var total = 0;

if (isNaN(price)) {
alert("Only enter numeric characters for the price");
return;
} else if (isNaN(taxRate)) {
alert("Only enter numeric characters for the tax rate");
return;
} else {
total = price + (price * taxRate);
alert("The total price is: \$" + total.toFixed(2));
}
}```

Now is a good time to note that the values of form fields are always strings. A user might type a number into a text field, but JavaScript still sees it as a string, which is where the `toNumber`, `isNaN`, `Number`, `parseFloat` and `parseInt` functions come into play. A closer look at both examples shows few differences in how they are written. The main difference is the level of tolerance for user generated errors. In Example 1, the `toNumber` function is used. This function removes all non-numeric characters from the string. If a user accidentally types a non numeric character before any numeric characters in one of the text boxes, the `toNumber` function is able to recover from that and still return a number.

In Example 2, if the user enters even one non-numeric character before a numeric character in one of the text fields, the `calcTax` function will alert the user of an error. In each example, the line of code with the `alert()` function call contains another golden nugget for working with numbers: the `toFixed` method of all `Number` variables.

###### Using the toFixed method to format numbers

This function is available for any `Number` variable in JavaScript, and allows you to specify how many decimal places you want to show. This function returns a string, and so most times is only usefull for displaying output to a user. It takes one parameter, an integer number of how many decimal places should be displayed.

```var num = 8.75249;

alert(num.toFixed(0)); // Shows the string 9
alert(num.toFixed(1)); // Shows the string 8.8
alert(num.toFixed(2)); // Shows the string 8.75
alert(num.toFixed(3)); // Shows the string 8.752
alert(num.toFixed(4)); // Shows the string 8.7525```

The `toFixed` function works similar to the `Math.round` function. In the first example, passing zero to `toFixed` returns 9, which is the same number that `Math.round` would return. The difference here is anything the `toFixed` function returns is a string, not a number.

In the second example, the number 1 is passed, so only one decimal place is shown. The decimal place just after .7, is .05. This .05 is rounded up to .1, and added to .7 to give a final string of "8.8". There may be a time, however, when you need to round a number to a certain number of decimal places and still have it be a number.

##### The round() function

There is no native `round` function in JavaScript that takes a number, rounds it to a certain number of decimal places, then returns a number. We'll call this function `round()`.

###### Function definition for round()
```/**
* round    Rounds a number to X decimal places
* @param   number (req)      Number to round. May also be string
* @param   int (opt)         Number of decimal places. Optional.
* @return  mixed             Null if NaN, or the rounded number
*/
function round(num, decimals) {
var multiplier = Math.pow(10, decimals);
if (typeof(num) != "number") {
return null;
}
if (typeof(decimals) != "number") {
var decimals = -1;
}
if (decimals > 0) {
return Math.round(num * multiplier) / multiplier;
} else if (decimals == 0) {
return Math.round(num);
} else {
return num;
}
}```

The `round()` function takes up to two parameters. The first is the number that should be rounded. The optional second parameter is the number of decimal places that should be rounded to. If this second parameter is omitted, the full floating point number is returned. If zero is passed as the second parameter, then the number is rounded up or down properly to an integer. If the second parameter is 1 or more, then the number is rounded to that many decimal places. The function returns an actual number, but if you give the `round()` function invalid data, null is returned.

##### Problems with round()

Normally you should only round a number to a decimal place when ouputing the number to the user. The function you'd want to use is the `toFixed` method of the `Number` class. If a calculation algorithm explicitly calls for a rounded number, then using the `round()` function above would be acceptable. If your algorithm does not explicitly call for a rounded number, then only round the number when outputing it to the user.

##### Preventing user number entry errors with textFieldToNumber

So far we've discussed converting strings to numbers, and accounting for user errors, but wouldn't it be nice to have a function that prevents user errors from ever occuring? Let's create one more function that cleans non-numeric characters from a string, and then apply it to a form text field.

```function textFieldToNumber(el) {
el.value = el.value.replace(/[^0-9-.]/g, "");
el = null;
}```

It's a pretty simple function. It strips out non numeric characters with a regular expression and puts the stripped down string back into the text field. Putting a number into a form field automatically converts it to a string. As you recall from earlier, form field values only contain strings. Next, we just need to attach the `textFieldToNumber` function to a form field.

```<form action="" method="get">

<input type="text" onblur="textFieldToNumber(this);" name="age">

</form>```

When the user presses the tab key or clicks off the form field, the onblur event fires, and then executes the `textFieldToNumber` function. A document object model node reference to the form field is passed to the function using the keyword `this`. The function removes any non numeric characters from the form field value, and then puts the pure number back in the form field. Since JavaScript can be disabled, make sure any server side script that receives data from your form double checks the input.

##### A Quick Recap

We've gone over a lot so far. Numbers in JavaScript are primitive and complex data type. The `Number` class has more functions and data members than this tutorial covers. Mathematical operators in JavaScript don't always do math. The addition operator (`+`) also joins two strings, and if you try adding a number to a string, the browser automatically converts the number to a string, and then joins the two strings.

We also learned the four main ways of converting strings to numbers: by subtracting a number from a string, using the `Number` class constructor, using the `parseFloat` function or using the `parseInt` function. The `parseInt` function needs the radix, or number base, passed to it each time. You might pass it a base 10 number with some funky input and get back a base 16, or hexadecimal number.

The `toNumber` function was written to convert strings to numbers in a more flexible manor than `parseFloat` and `parseInt`. The native `isNaN` function can detect if a variable doesn't contain a number value, and is used for detecting user errors in the data. Once valid numbers have been tested for, we touched on how to round numbers using `Math.round` and the `toFixed` method of the `Number` class. We also created a `round()` function that returns a number rounded to a certain decimal place, rather than using the `toFixed` method which returns a string. Lastly, the custom function `textFieldToNumber()` can be attached to a form field and prevents user errors when entering numbers.

There is much more about numbers and JavaScript that this tutorial hasn't covered, however these are the basics and all you should need 90 percent of the time. Other useful resources are listed below: