JavaScript is the only language, developers don’t learn to use before using it.
Mostly developers say that JavaScript don’t have types as we don’t need to explicitly mentioned type when declaring variables.
That’s why we need to provide extra focus on types. Becaues if we don’t then it would implicitly convert or change the behavior.
For example, 18 and "18" are different for JavaScript Engine.
One is Number, another is String.
There’s no point to debate whether JavaScript has data types or not. Being developer, we should aware about each type and its behaviors.
Table of contents
Open Table of contents
Built-in Data Types
JS has built-in seven types:
- null
- undefined
- boolean
- number
- string
- symbol
- object
Everything except
objectis of primitive types.
typeof
In JavaScript, we can use typeof to inspect the data type of the value.
typeof undefined; // "undefined"
typeof null; // "object" , JS bug (gotcha)
typeof "Sagar"; // "string"
typeof 18; // "number"
typeof "18"; // "string"
typeof { name: "Sagar" }; // "object"
typeof true; // "boolean"
typeof Symbol(); // "symbol"
Buggy Behavior:
typeof nullreturns object.
Value Types
Like other languages (C, C++, Java), JavaScript variables don’t have data types. Javascript has value types.
var x = "Sagar";
x = 30;
Variable can hold string in one assignment, and number next.
undefined vs. undeclared
Variable is undefined, if it has no value. It is not same as undeclared.
undefined has been declared and accessible in the scope, but has no value. undeclared variable is not accessible in the given scope.
var a;
a; // undefined
b; // undeclared, ReferenceError
typeof a; // undefined
typeof b; // undefined
Arrays
Javascript arrays are containers that can hold any value types. While other language enforce you to have all values of same type.
var a = [11, "2", [333]];
a[0]; // 11
a[2][0]; // 333
// Sparse Array
var a = [];
a[0] = 11;
// a[1] => undefined
a[2] = 33;
Note: Be careful when creating sparse arrays. (Empty slots in between)
Arrays have numerical index. You can also add string keys.
String keys won’t be counted when counting length of the array.
var a = [];
a[0] = 11;
a[1] = 33;
a["name"] = "Sagar";
a.length; // 2
// [GOTCHA]
var a = [];
a["15"] = 18;
a.length; // 16
Strings
Understanding of String might be array of characters. It may not use Array.
But when writing code, it’s hard to differentiate.
var a = "foo";
var b = ["f", "o", "o"];
a.length; // 3
b.length; // 3
a.indexOf("o"); // 1
b.indexOf("o"); // 1
var c = a.concat("bar"); // "foobar"
var d = b.concat(["b", "a", "r"]); // ["f","o","o","b","a","r"]
a === c; // false
b === d; // false
Both are array of characters, right? Not Actually.
a[1] = "O";
b[1] = "O";
a; // "foo", unchanged, strings are immutable
b; // ["f", "O", "o"], arrays are mutable
Many of the array methods can be useful for string, but not available.
Workaround
- Convert
string→array - Perform the desired operation using
arraymethod - Convert
array→stringagain
var a = "ABCD";
var b = a
.split(" ") // Convert to array
.reverse() // Perform array operation
.join(""); // Convert to string
console.log(b); // "DCBA"
Numbers
JavaScript has one Numeric type. It includes:
- Integer
- Fractional Decimal Numbers
Numbers are expressed as base-10 decimal literals.
var a = 18; // 18.0 - 0 is optional
var b = 18.7;
var a = 0.45; // .45 - leading 0 is optional
var a = 18.0; // 18. - trailing 0 is optional - weird syntax, but valid
.toFixed() specify how many fractional decimal places to represent value with.
var a = 18.745;
a.toFixed(0); // "19" - round off to near decimal
a.toFixed(1); // "18.7"
a.toFixed(2); // "18.75"
a.toFixed(3); // "18.745"
a.toFixed(4); // "18.7450"
a.toFixed(5); // "18.74500"
.toPrecision() specify how many digits should be used to represent the value.
var a = 18.745;
a.toPrecision(1); // 2e+1
a.toPrecision(2); // "19"
a.toPrecision(3); // "18.7"
a.toPrecision(4); // "18.75"
a.toPrecision(5); // "18.745"
a.toPrecision(6); // "18.7450"
a.toPrecision(7); // "18.74500"
Can’t use number directly with this function
18.toFixed(3); // Syntax Error
// Alternate Solutions
(18).toFixed(3); // "18.000"
0.457.toFixed(4); // "0.4570"
18..toFixed(3); // "18.000" (double dots)
18 .toFixed(3); // "18.000" (space before dot)
Decimal Values
0.1 + 0.2 === 0.3; // false
0.1 and 0.2 in binary floating point are not exact. When they are added result is not exactly 0.3. It’s really close 0.30000000000000004
To solve this, we can use Number.EPSILON to compare two numbers for equality.
function numberEquals(n1, n2) {
return Math.abs(n1 - n2) < Number.EPSILON;
}
var a = 0.1 + 0.2;
var b = 0.3;
numberEquals(a, b); // True
Special Values
null is an empty value.
undefined is a missing value.
null had a value and doesn’t anymore. undefined hasn’t had value yet.
Any operation you perform without both operands as numbers will fail to produce valid number and resulted into NaN.
NaN is “Not a Number”. Same as “Invalid Number” or “Bad Number”.
// [GOTCHA]
typeof NaN; // "number"
NaN === NaN; //false
For comparison, we should use Number.isNaN() instead of === .
var a = 18 / "King";
var b = "king";
Number.isNaN(a); // true
Number.isNaN(b); // false
Infinity
Divided by zero results to Infinity. JS result to Infinity or -Infinity.
var a = 1 / 0; // Infinity
var b = -1 / 0; // -Infinity
a = Number.MAX_VALUE;
a = a + a; // Infinity
Type of Zero (0 and -0)
Javascript has two type of zero:
- normal zero (0)
- negative zero (-0)
var a = 0 / -7; // -0
var b = 0 * -7; // -0
Addition and subtraction can’t result into negative zero.
// [GOTCHA]
var a = 0; // 0
var b = 0 * -7; // -0
a == b; //true
-0 == 0; // true
a === b; // true
a > b; // false
Only way to compare 0 and -0.
1 / 0; // Infinity
1 / -0; // -Infinity
Value vs. Reference
Primitive(simple) types are passed by value:
- null
- undefined
- string
- number
- boolean
- symbol
Compound values(object) create copy of reference on passing.
- arrays
- functions
- objects
// Pass by value
var a = 1;
var b = a;
a = 2;
a; // 2
b; // 1
// Pass by reference
var a = [1, 2, 3];
var b = a; // same reference
b === a; // true
b = [1, 2, 3]; // reference changed
b === a; //false
b = a;
a = [4, 5, 6];
b; // [1,2,3]
a; // [4,5,6]
Coercion
Type Casting
- converting value from one type to another externally
- happens in statically typed language at compile-time
Coercion
- converting value from one type to another implicitly (Forced by Rules)
- happens in dynamically typed language at run-time
var a = 18;
var b = a + ""; // Implicit coercion
var c = String(a); // Explicit coercion
toString()
When any non-string value is coerced into string, conversion handled by toString() method.
- null becomes “null”
- undefined becomes “undefined”
- false becomes “false”
Objects will use default Object.prototype.toString(), if you don’t override with your own implementation.
Arrays have default toString() which concatenate all values with comma seperated.
var a = [1, 2, 3];
a.toString(); // "1,2,3"
ToNumber
When any non-number value used in a way where it’s required to be number, such as mathematical operation then it will use ToNumber operation.
- true becomes 1
- false becomes 0
- undefined becomes NaN
- null becomes 0
ToBoolean
In JavaScript, 1 and true & 0 and false are not same. Other languages, it might be true.
For JavaScript, one is number and another is boolean. We can coerce 0 to false, 1 to true.
Falsy Values Only below values in JS are falsy values, rest all are truthy values.
- undefined
- null
- +0
- -0
- NaN
- false
- ""
All values except above values treats as truthy value when coercion will be happened in JavaScript.
Explicit Coercion: Between String and Numbers
This is simple and most common coercion.
We can use built-in String() and Number() functions.
var a = 18;
var b = String(a); // "18"
var c = "3.14";
var d = Number(c); // 3.14
Other ways to convert these values are in below example:
var a = 18;
var b = a.toString(); // "18"
var c = "3.14";
var d = +c; // 3.14, unary operator form
var e = -c; // -3.14, - flip the sign and convert
Parsing Numeric Strings
We have built-in parseInt() or parseFloat() methods to parse numeric string.
It stops parsing from left to right when non numeric character encounters.
var a = "18";
var b = "18runs";
parseInt(a); // 18
parseInt(b); // 18
Parsing vs Coercion
Parsing a numeric value from string is tolerant of non-numeric characters. Coercion is not tolerant and fails, it resulted into NaN.
var b = "18runs";
Number(b); // NaN , coercion
parseInt(b); // 18 , parsing
Explicit Coercion to Boolean
Boolean() is explicit way to force ToBoolean coercion.
Like + opeator coerce to Number.
! operator coerce to Boolean. Problem is that it negates the value as well. So we have to flip the value again by adding one more !
var a = "O";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g; // undefined
!!a; // true
!!b; // true
!!c; // true
!!d; // false
!!e; // false
!!f; // false
!!g; // false
Loose Equality Coercion (==)
var a = 42;
var b = "42";
a == b; // true
What kind of coercion happens here?
a becomes string or b becomes number?
Below rules followed for this kind of coercion:
- If Type(x) is
Numberand Type(y) isString,
return the result of the comparison x== ToNumber(y). - If Type(x) is
Stringand Type(y) isNumber,
return the result of the comparisonToNumber(x) == y.
convert string to number
Comparison anything to boolean
var a = "42";
var b = true;
a == b; // false
Below rules followed for coercion from Boolean to Number:
- If Type(x) is
Boolean,
return the result of the comparisonToNumber(x) == y. - If Type(y) is
Boolean,
return the result of the comparisonx == ToNumber(y).
Steps:
- converted true to 1
- check both are same type and number
- convert “42” to 42
- compare 42 == 1, results to false
convert boolean to number
Comparing null to undefined
var a = null;
var b; // undefined
a == b; // true
a == null; // true
b == null; // true
Rules:
- If x is null and y is undefined, return true.
- If x is undefined and y is null, return true.
Comparing object to non-object
If object(object/function/array) compare to simple primitive type, then ES5 specs say:
- If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison
x == ToPrimitive(y). - If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison
ToPrimitive(x) == y.
convert object to primitive type
var a = 42;
var b = [42];
a == b; // true
// Steps:
// 1. [42] converts to "42" as ToPrimitive coercion
// 2. 42 == "42" still different type
// 3. "42" converts to 42 (number)
// 4. 42 == 42 , return true
var a = "abc";
var b = Object(a);
a == b; // true
// Steps:
// 1. b is coerced to underlying "abc" primitive value
// 2. both are same "abc" == "abc", return true
Falsy Comparisons
"0" == null; // false
null is only loosely equal to undefined But null is not equal to anything else even with coercion.
"0" == undefined; // false
No type conversion happens with null and undefined if they compare it with other types than null and undefined.
Coercion Examples with Steps
"0" == false; // true
// Steps:
// 1. false -> 0
// 2. "0" == 0
// 3. "0" -> 0
// 4. 0 == 0 // true
"0" == NaN; // false
// Steps:
// 1. "0" -> 0 (string to number)
// 2. 0 == NaN (anything equals to NaN => false)
// NaN is not equal to anything
"0" == ""; // false
// Steps:
// 1. no coercion as both strings
// 2. both strings are not same so false
false == null; // false
false == undefined; // false
0 == null; // false
0 == undefined; // false
"" == null; // false
"" == undefined; // false
"" == NaN; // false
// null and undefined only compare with themselves. Not with anything else. So false in this scenarios as well.
false == NaN; // false
// Steps:
// 1. false -> 0
// 2. 0 == NaN // false
// NaN is not equal to anything
false == "";
// Steps:
// 1. false -> 0
// 2. 0 == ""
// 3. "" -> 0
// 4. 0 == 0 // true
false == {}; // false
// Steps:
// 1. false -> 0
// 2. 0 == {}
// 3. {} toPrimitive "[object Object]"
// 4. 0 == "[object Object]"
// 5. "[object Object]" -> NaN
// 6. 0 == NaN
// Anything equals to NaN is false.
"" == NaN; // false
0 == NaN; // false
"foo" == ["foo"]; // true
// Steps:
// 1. ["foo"] convert to primitive
// 2. toString() converts it to "foo"
// 3. "foo" == "foo" // true
Refer this JS Comparisons Table for all possible combinations.
Thank you for reading long article about JS types and coercion in details.
Connect with me on X or LinkedIn, if you have any feedback or suggestion.