JavaScript uses a dynamically typed, weakly typed, runtime-evaluated type system.
let x = 10; // number
x = "10"; // string
x = true; // boolean
No static type locking exists at the language level.
JavaScript data types are divided into:
numberbigintstringbooleanundefinednullsymbolobject
numberIEEE-754 double-precision floating point (64-bit).
let a = 10;
let b = 10.5;
let c = -3;
let d = Infinity;
let e = NaN;
Properties
NaN is a number typetypeof NaN; // "number"
Number.isNaN(NaN); // true
NaN === NaN; // false
Precision Pitfall
0.1 + 0.2 === 0.3; // false
bigintFor integers larger than Number.MAX_SAFE_INTEGER.
let x = 9007199254740993n;
Rules:
n suffixnumber10n + 5n; // valid
10n + 5; // TypeError
stringImmutable UTF-16 encoded sequence.
let s1 = "hello";
let s2 = 'hello';
let s3 = `hello ${2 + 2}`;
Immutability:
let s = "abc";
s[0] = "z";
console.log(s); // "abc"
booleanTwo values only.
true
false
Often produced implicitly via coercion.
undefinedIndicates absence of assignment.
let x;
x === undefined; // true
Returned when:
nullExplicit intentional absence of value.
let y = null;
Historical bug:
typeof null; // "object"
symbolUnique, immutable identifiers.
let id = Symbol("id");
let id2 = Symbol("id");
id === id2; // false
Used for:
objectEverything non-primitive is an object.
let obj = {};
let arr = [];
let fn = function(){};
Reference Semantics
let a = { x: 1 };
let b = a;
b.x = 2;
console.log(a.x); // 2
typeof Operator Behavior| Value | typeof |
|---|---|
123 |
"number" |
"hi" |
"string" |
true |
"boolean" |
undefined |
"undefined" |
null |
"object" ❌ |
{} |
"object" |
[] |
"object" |
function(){} |
"function" |
Symbol() |
"symbol" |



Type Coercion = automatic conversion of one type to another.
Two categories:
+ operator)The + operator in JavaScript is overloaded. It performs either numeric addition or string concatenation, depending on runtime operand types and evaluation order. No other operator behaves this way.
Core Rule (Non-Negotiable)
+ is a string, the operation becomes string concatenationCritical Insight: Left-to-Right Binding
+ at a time, strictly left-to-right1 + "2"; // "12"
"1" + 2 + 3; // "123"
1 + 2 + "3"; // "33"
+ — Exact Evaluation SemanticsExample 1
1 + "2"; // "12"
1 → number"2" → string1 is coerced to "1""1" + "2" → "12"Example 2
"1" + 2 + 3; // "123"
Step 1: "1" + 2
"1" is string → concatenation2 → "2""12"Step 2: "12" + 3
"12" is string → concatenation3 → "3""123"Example 3
1 + 2 + "3"; // "33"
Step 1: 1 + 2
3Step 2: 3 + "3"
3 → "3""33"Example 4: String in the Middle
10 + "5" + 2; // "1052"
Steps:
10 + "5" → "105""105" + 2 → "1052"Example 5: String at the End
10 + 5 + "2"; // "152"
Steps:
10 + 5 → 1515 + "2" → "152"Example 6: Parentheses Override Order
10 + ("5" + 2); // "1052"
Steps:
"5" + 2 → "52"10 + "52" → "1052"Example 7: Boolean Coercion
true + "1"; // "true1"
false + 1; // 1
Explanation:
true + "1" → string concatenationfalse + 1 → numeric addition (false → 0)Example 8: Null and Undefined
null + "1"; // "null1"
undefined + "1"; // "undefined1"
null + 1; // 1
undefined + 1; // NaN
Why:
null → 0 in numeric contextundefined → NaNExample 9: Arrays (Hidden String Conversion)
[] + 1; // "1"
[1,2] + 3; // "1,23"
Steps:
[] → ""[1,2] → "1,2"Example 10: Objects
{} + "1"; // "[object Object]1"
Object → toString() → "[object Object]"
- * / %)All non-string operators force numeric conversion.
"10" - 2; // 8
"10" * 2; // 20
"10" / 2; // 5
"10" % 3; // 1
Invalid numeric → NaN.
Only + performs string concatenation.
"10" - 2; // 8
"10" * 2; // 20
"10" / 2; // 5
All other arithmetic operators force numeric coercion.
+ = context-sensitiveAny expression containing + and untrusted input is type-unsafe unless explicitly converted.
Correct pattern:
Number(a) + Number(b)
Incorrect assumption:
a + b
Falsy values:
false0-00n""nullundefinedNaNEverything else is truthy.
if ("0") { } // executes
if ([]) { } // executes
if ({}) { } // executes
== vs ===)===)"5" === 5; // false
==)Follows complex coercion rules.
Key cases:
"5" == 5; // true
null == undefined; // true
false == 0; // true
"" == 0; // true
[] == 0; // true
Object Comparison
[] == []; // false (reference)
When using ==:
null == undefined → truevalueOf() → toString()Example:
[] == 0
[] -> "" -> 0
Number("10"); // 10
+"10"; // 10
parseInt("10"); // 10
parseFloat("10.5"); // 10.5
Differences:
Number("10px"); // NaN
parseInt("10px"); // 10
String(123); // "123"
(123).toString();// "123"
Boolean(0); // false
Boolean("hi"); // true
!!"hi"; // true
Object.is() vs ===Object.is(NaN, NaN); // true
NaN === NaN; // false
Object.is(+0, -0); // false
+0 === -0; // true
let sum = a + b; // b from input → string
if ("false") { } // executes
[] + [] // ""
[] + {} // "[object Object]"
{} + [] // 0 (context-dependent)
=== alwaysNumber.isNaN() instead of isNaN()null and undefined as semantically distinctbigint and numbertypeof null is broken by design== = legacy convenience=== = correctness