There are three basic data types: "Boolean", "Number", "String". Values of the corresponding types are returned by Boolean(x), Number(x), String(x) for any x.
There are compound data types :- the type "Object" includes "Array" and "RegExp" as subtypes.
An Object contains something like a table of name-value pairs.
There are six permissible String return values of the operator typeof :- "boolean", "function", "number", "object", "string", "undefined".
Note that input controls return only Strings, even if the input looks like a number; and that the binary operator + is a string concatenator if at least one of its two operands is a string ...
Strings are made of 16-bit Unicode characters. There is no practical upper limit on their length; empty strings are not special.
Literal strings are bounded by matching " or ' characters, and so can contain the other character. The escape character is \ which accordingly is represented by \\; other particular cases are \" \' \n \t \x## \u#### for " ' newline, tab, hexadecimal ##, and Unicode hexadecimal #### - \x## = \u00##.
Within code, Strings should generally not be used to represent numbers or Booleans. String input can be converted on input with unary + or !! operators respectively, as below.
When a variable is used to store one of two states, the Boolean values true / false should generally be used. It is inefficient to store, for example, Strings "yes" / "no" if those forms are not used as such for I/O.
When a Boolean is required, only the following values are
considered to mean false :-
0 (numeric zero), "" (empty string), false, NaN, null, undefined.
The unary NOT operator ! gives a Boolean result from an argument of any type.
The following operators all give a Boolean result :-
! < <= > >= == != === !== && ||
Boolean() converts its argument to Boolean, as does the dual-unary operator !!. The following should be equivalent :-
DocProp = (document.Prop?true:false) DocProp = Boolean(document.Prop) DocProp = document.Prop != null DocProp = !!document.Prop
Number(BoolExp) and +BoolExp return 0 if the expression is false and 1 if it is true.
The following should not be used :- X==true X!=false X==false X!=true - instead, use respectively :- X X !X !X.
There are special values :-
Integers can only be held accurately up to 53 bits plus sign, and numbers are only, at best, accurate to 15-16 significant decimal digits. Any integer from 0 up to 253 = 9,007,199,254,740,992 in magnitude is stored exactly, but relatively few decimal fractions can be. Only the numbers obtainable from one of those integers by multiplying by 2N-53 for any N in -1023 to +1023 can be held exactly. Check in detail, though.
For conversion of ordinary values of Number to/from bit strings, and the exact value of Numbers, see in Exact Arithmetic.
A general understanding of the properties and use of floating-point numbers is necessary for almost any arithmetic beyond counting; see Pascal Floating-Point for links to general information on floating-point numbers and arithmetic, and Pascal / Delphi / + Types for data on type Double. IEEE Doubles are handled directly by the FPU of a PC; I don't know the situation on other processors.
Seek the edited reprint (large: 500K + graphics) of a paper What Every Computer Scientist Should Know About Floating-Point Arithmetic, by David Goldberg, (1991); while parts are esoteric, much is easy to read. One URL.
Given that Numbers are Doubles, arithmetic is as exact as possible, but no more. Simple binary fractions are exact, provided no more than 53 bits in all are needed. Operations on integers are exact if the true result and all intermediates are integers within that range, except where bitwise operators are used, when the range is 32-bit.
Note that pound-pence arithmetic, using values such as £12.34, may have unexpected small errors; I find that 3355.53 + 660.97 - 660.97 evaluates to 3355.5299999999997. Do the arithmetic in pence - 335553 + 66097 - 66097 gives 335553 - or be sure to round to pence sufficiently often. 1142.33 + 44545.66 gives 45687.990000000005.
And 1.26+11.67+3.45+2.97 evaluates to 19.349999999999998, not 19.35. Indeed, 0.05+0.01 gives 0.060000000000000005 and 0.06+0.01 gives 0.06999999999999999. Also, -0.07+0.05+0.02 gives -3.469446951953614e-18; this illustrates that code to output non-negative numbers as strings may need to accommodate slightly negative ones.
And 3*0.1 gives 0.30000000000000004, and 1.1*1.1 evaluates to 1.2100000000000001.
Note that, while A+B = B+A, it may be that A+B+C != C+B+A, since that is a comparison of (A+B)+C and (C+B)+A which may round differently; for example, X = [0.03+0.03+0.01, 0.01+0.03+0.03] gives me [0.06999999999999999, 0.07].
Where it is known that a calculated number should have an integer value, one can use Math.round() directly to remove its rounding errors.
In particular, non-integer computed results should not normally be compared for equality; and generally need rounding for display.
For example, X*0.01 often differs slightly from X/100 - the latter is better, since 100 is stored exactly and 0.01 cannot be. Example : X = 35.
There must be a danger with Math.trunc() / Math.ceil(), in cases where the argument should ideally be an exact integer, that rounding errors may have placed it on the "wrong side" of the exact value, after which trunc / ceil will give a result differing by one from what it should ideally be.
The unary + - operators.
The following bitwise operators - ~ << >> >>> & ^ | - work on 32-bit integers; conversion to/from Number is automatic. They are, respectively, complement, shift left, shift right arithmetic, shift right, and, xor, or.
They repay consideration; they seem fast. See in Uses of Operators.
In any case where it may matter, it is important to check the behaviour of any "float-to-integer" type of operation for negative arguments; and any rounding for "half-way" arguments.
Mod on negative numbers has the usual difference from what I
generally need; it gives :-
(-33 % 10) → -3 rather than → +7 .
A workround is to add a sufficient multiple of the second argument to the first.
However, Math.floor is as I would wish :-
Math.floor(-2.5) → -3 and not → -2.
Thus the following code gives the Mod that I prefer, an alternative, and a more expressive Div. Note : Mod & mod give different results for negative Y and can give slightly different results for non-integer Y.
For numbers in the signed 32-bit range, X|0 truncates X towards zero; it seems quicker than Math.floor(X).
For the fractional part of X, use X % 1.0 or Mod(X, 1.0).
See also Pascal Maths.
Assigning a value which is a simple number, string, or boolean creates a new copy; changing the copy does not change the original. This is "Pass by Value".
Assigning an Object entity creates a new copy of the pointer to that entity; the original Object is not duplicated. Likewise for Arrays, which are in fact Objects themselves; and String Objects. This is "Pass by Reference".
These appear to behave as for Assignments. Parameters are passed by value, and the value of an object for this purpose is effectively a pointer to it.
So the external values of simple parameters cannot be changed; but the properties of objects can be.
"Objects, including Arrays, are passed by reference. Simple variables are always passed by value."
A string of digits starting with a zero is sometimes considered to be in octal - only, I think, for numeric literals, and when parseInt() has no second parameter, in which case octal seems probable but deprecated. So parseInt("09") cannot be trusted. A string starting 0x is by default taken as hexadecimal.
Results and arguments which represent angles are in radians; one circle equals 2π radians equals 360 degrees equals 400 grads equals 6400 mils. Don't enter a numeric value for π, etc.; use Math.PI, etc., assigning its value to a variable if brevity is needed. Note that canvas routines use radians, but SVG routines use degrees.
See also Pascal Maths.
Stirling's approximation, to sufficient terms, can also be used to calculate the logarithm of the factorial.
Note that, in some circumstances, a value 231 ≤ N < 232 may be shown in Hex as a number in 0..0x7fffffff preceded by a minus sign; and that this may be browser-dependent.
That uses parsefloat(X, base).toString(radix); the input values are NOT validated. Even where that approach is unsuitable, there can be no need to use Math.pow(). Try it with the output base not 10 and the output value large!
Currently (June 2010). .toString(radix) is not cross-browser reliable with non-integer Numbers; the final character can for example be the radix, or zero.
The operation N = N & N-1 decrements the number of bits set in N; somewhere, there is a Web page listing many such operations.
The Decimal Separator (decimal point), where needed, is vital; but thousands separators are mere decoration.
Consider multi-national number formats.
Data which is stored or transmitted should not use a localised format; the format should be fixed and where possible compliant with standards of ISO and similar bodies.
If you see a comma (',') reported as the decimal separator, please tell me : I do not expect it to occur.
S = S.replace(/,/, '.') // for input S = S.replace(/\./, ',') // for output
For integers with thousands separators, use the above in the opposite order and with a RegExp g modifier.
For strings with both separators possible, to exchange dot and comma throughout,
S = S.replace(/,/g, '#').replace(/\./g, ',').replace(/#/g, '.')
It may be required that a Number is converted to String, with integers having trailing ".0". Function TRZ converts integers, without harming or rounding other Numbers.
Consider multi-national number formats. Before a thousands separator, India prefers separators two digits apart, to show lakhs, crores, etc. The following can be changed to insert dot rather than comma.
Note that ThouS is for non-negative integers, and Comma is for integers.
To insert commas as thousands separators :-
Unicode "\u20AC" is the Euro sign, "€" or "€"; "\u00A3" is the Pound sign, "£". Function RComma() can process more than one number in a string. A "g" does not affect the result; and, in MSIE 4, it did not significantly affect the speed. See Regular Expressions.
See Indian numbering system.
Commas can be removed from a string for input :-
S = S.replace(/,/g, '') S = S.split(',').join()
After possible pre-processing, the quantity represented by an input string may need to be used as a Number. If so, usually it should immediately (but after any pattern validation; see RegExps & Validation) be converted to Number type.
One can use, to convert String S to Number, any of : +S -S Number(S) parseInt(S) parseInt(S,B) parseFloat(S), or any other operator requiring an arithmetic operand. Different converters have differing properties.
Unlike the unary operators, parseFloat/parseInt disregard trailing non-numerics. All of those conversions disregard whitespace; all disregard leading zeroes, except sometimes for parseInt(S).
The unary + operator converts its argument to type "number". For converting String to Number, it seems preferable to parseInt / parseFloat except when their special properties are required. It is shorter and faster.
Unary + is a good way to fix the '1' + '1' = '11' problem (FAQ, 6.4). In reading a control, V1 = + document.forms['AForm'].Min1.value makes V1 a number; without the + it still would be a string.
While typeof(0+'') gives 'string', typeof(+'') gives 'number'.
The unary - operator is similar; so - - (not --) is in effect a numeric + operator.
They take numbers as decimal unless starting with 0x (or 0X), meaning hexadecimal; a leading zero does not mean octal. Leading whitespace is ignored; leading or trailing non-numerics give NaN. An empty string gives zero.
See also The unary + operator by Brad Fults.
Number() can be expected to behave as unary +.
S+0 S-0 S*1 S/1 are deprecated, as calling for an unnecessary operation; use +S.
Remember that if parseInt is given only one argument, and that starts with zero, then the argument is generally taken as octal (unless starting with 0x, when as hexadecimal); giving two arguments is safer. Except for leading whitespace and sign, the first non-numeric character terminates the number.
Remember that a literal integer is interpreted as hexadecimal if the numeric part starts with 0x.
Function parseInt(S, 10) can be used to read the integer part of a decimal fixed-point number, independently of which decimal separator is used, if any.
When a zero is returned by parseInt / parseFloat, it is correctly signed.
For converting a possibly signed base-B digit string S to a Number, function parseInt should be used only when beneficial, as it is longer and slower than alternatives.
For values of numeric properties, given in decimal without a leading zero and possibly followed by a unit (such as when getting the value of a style property, e.g. 33px), parseInt(S) is appropriate.
Bases 2 to 7, 9, 11 to 15, 17 to 36 always require parseInt(S, B).
In bases 8, 10 and 16, a string S of non-negative integer value with non-numeric parts removed (e.g. 09kg has been trimmed to 09), can be of the forms :-
S B Conversion Note 0123 8 use parseInt(S, 8) 1 0123 10 unary + preferred 2 2345 10 unary + preferred 2 0x6b4 16 unary + preferred 6b4 16 use parseInt(S, 16) Notes : 1: B is needed to work with all browsers and with ECMA-262 3rd Edn 2: Commonly use parseInt when converting the value of form controls to Number
Note : +'0x1' differs from parseFloat('0x1') and +'' differs from parseFloat('').
ECMA-262's global function parseFloat is decimal-only, handling such as 3.142 864e5.
For approximate and exact routines, see in Exact Arithmetic.
For rounding to a given number of decimal places or significant figures, see my Rounding 0.
Only a string can have a leading zero; these functions always return a string. Some of these, and others, are tested and timed at String and Number Formatting.
To bring integers in 0-9 to two digits, or 0-99 to three digits, by adding leading zeroes, without mistreating out-of-range numbers :-
This may sometimes be better; it also accepts Number parameters, and Hex strings (==1 or <2 ?) :-
This prefixes single digits within word boundaries throughout :-
For more, use SpcsTo() / ZeroTo / ChrsTo, or build on one of PadNumber#() which assume Num>=0.
Script version ≥ #1
Use at your own risk; it is not tested enough for use with real currency or on cheques.
Is there interest in the reverse operation?
For a Number X which may be negative, use Math.abs(X) after dealing with the sign.
For non-integers, obtain the integer and fractional parts of the Number X with |0 %0 and treat separately.
Arithmetic on non-integers is usually inexact, but sometimes, with cate and understanding, it can be made strictly exact.
Money calculations using integer-euros-point-cents will be unreliable. It is generally better to work in integer cents; it may be useful to work in submultiples (such as Delphi's "currency", a 64-bit integer "comp" scaled by 10000).
Subtraction of similar non-integers leads to increased relative errors. For example, the algebraic formula for the roots of a quadratic includes a ± sign. Rather than using both directly, it will be better to obtain the first root by whichever sign gives an augmentation and the second by then using the formula for the ratio of the roots.
Where possible, remove factors common to the numerator and denominator of an overall expression, as in B = π * A ; ... ; C = B / π ; and similarly with addition and subtraction.
It is better to multiply or divide by an integer than to divide or multiply by its reciprocal. To see that there can be a difference, evaluate 35/100 - 35*0.01 for example.
Getting a base-10 lograrithm by dividing a base-e logarithm by a constant is inexact. Try Math.log(1000)/Math.log(10) for example.
Converting from exact algebra to optimum executable code is an art which should be attempted only with care and consideration.