[{"data":1,"prerenderedAt":174},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Ffundamentals\u002Fdata-types-coercion":3},{"page":4,"siblings":165,"blog":171},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"related":156,"seo":157,"seoDescription":158,"stem":159,"subtopic":160,"topic":161,"topicSlug":162,"updated":163,"__hash__":164},"qa\u002Fjavascript\u002Ffundamentals\u002Fdata-types-coercion.md","Data Types Coercion",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,"\u002Fjavascript\u002Ffundamentals\u002Fdata-types-coercion",[22,27,31,35,39,43,47,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152],{"id":23,"difficulty":24,"q":25,"a":26},"primitives","easy","What are the primitive types in JavaScript?","There are **seven primitive types**: `string`, `number`, `boolean`, `null`,\n`undefined`, `symbol`, and `bigint`. Everything that isn't a primitive is an\n**object** — and that includes arrays, functions, dates, and `null`'s\nmisleading `typeof`.\n\n```js\ntypeof 'hi'        \u002F\u002F 'string'\ntypeof 42          \u002F\u002F 'number'\ntypeof true        \u002F\u002F 'boolean'\ntypeof undefined   \u002F\u002F 'undefined'\ntypeof Symbol()    \u002F\u002F 'symbol'\ntypeof 10n         \u002F\u002F 'bigint'\ntypeof null        \u002F\u002F 'object'  \u003C- historical bug, null IS a primitive\n```\n\nTwo defining traits: primitives are **immutable** (you can't change the value\nitself, only rebind the variable) and they're **compared by value**, whereas\nobjects are mutable and **compared by reference**. When you call a method like\n`'hi'.toUpperCase()`, JS temporarily wraps the primitive in an object\n(autoboxing) and discards it afterward.\n",{"id":28,"difficulty":24,"q":29,"a":30},"eqeq-vs-eqeqeq","What is the difference between == and ===?","`===` is **strict equality**: it compares **value *and* type** with no\nconversion — if the types differ, it's immediately `false`. `==` is **loose\nequality**: it **coerces** the operands toward a common type first, which\nproduces a list of surprising results.\n\n```js\n0 === ''      \u002F\u002F false (number vs string)\n0 == ''       \u002F\u002F true  (both coerce to 0)\n0 == '0'      \u002F\u002F true\n'' == '0'     \u002F\u002F false  \u003C- not even transitive!\nnull == undefined \u002F\u002F true (special-cased)\nNaN == NaN    \u002F\u002F false\n[] == ![]     \u002F\u002F true  (classic \"wtf\" — [] coerces to '', ![] is false -> 0)\n```\n\n**Prefer `===` virtually always** — it's predictable and the coercion rules\nbehind `==` are a frequent bug source. The one common idiomatic exception is\n`x == null`, which conveniently matches *both* `null` and `undefined`.\n",{"id":32,"difficulty":14,"q":33,"a":34},"coercion","What is type coercion?","Coercion is JavaScript **automatically converting** a value from one type to\nanother. It comes in two flavors: **implicit** (the engine does it for you\nduring an operation, e.g. `'5' * 2`) and **explicit** (you ask for it,\n`Number('5')`, `String(5)`, `Boolean(0)`).\n\nThe operator that trips everyone up is `+`: if **either** side is a string, it\ndoes **string concatenation**; otherwise it does numeric addition. The other\narithmetic operators (`-`, `*`, `\u002F`) have no string meaning, so they coerce to\nnumbers.\n\n```js\n1 + '2'    \u002F\u002F '12'   (+ with a string -> concatenation)\n1 - '2'    \u002F\u002F -1     (- forces numeric -> 1 - 2)\n'5' * '2'  \u002F\u002F 10     (* forces numeric)\ntrue + 1   \u002F\u002F 2      (true -> 1)\n[] + {}    \u002F\u002F '[object Object]'  (both -> strings)\n```\n\nIn an interview, narrate the rule (\"`+` prefers strings, the rest prefer\nnumbers\") rather than memorizing every edge case.\n",{"id":36,"difficulty":24,"q":37,"a":38},"truthy-falsy","Which values are falsy in JavaScript?","There are exactly **eight falsy values** — memorize the list, because\n*everything else is truthy*:\n\n```js\nfalse\n0\n-0\n0n        \u002F\u002F BigInt zero\n''        \u002F\u002F empty string\nnull\nundefined\nNaN\n```\n\nThe famous gotchas are the things people *expect* to be falsy but aren't:\n`'0'`, `'false'`, `[]` (empty array), and `{}` (empty object) are **all\ntruthy**.\n\n```js\nif ([]) console.log('runs!')   \u002F\u002F empty array is truthy\nif ('0') console.log('runs!')  \u002F\u002F non-empty string is truthy\nBoolean([]) \u002F\u002F true\n```\n\nThis matters for `if` conditions, `||`\u002F`&&`, and the nullish coalescing\noperator `??` (which, unlike `||`, only falls back on `null`\u002F`undefined`, not\non `0` or `''`).\n",{"id":40,"difficulty":14,"q":41,"a":42},"null-undefined","What is the difference between null and undefined?","Both represent \"no value,\" but they signal different *intents*:\n\n- `undefined` is the language's default \"absence\" — a declared-but-unassigned\n  variable, a missing object property, a missing function argument, or the\n  return of a function with no `return`. The **engine** produces it.\n- `null` is an **intentional, explicit** \"no value here\" that **you** assign to\n  say \"this is deliberately empty.\"\n\n```js\nlet a               \u002F\u002F undefined (never assigned)\nconst obj = {}\nobj.missing         \u002F\u002F undefined (no such property)\nconst b = null      \u002F\u002F null (you chose emptiness)\n\ntypeof undefined    \u002F\u002F 'undefined'\ntypeof null         \u002F\u002F 'object'  \u003C- long-standing bug, never fixed for compat\nnull == undefined   \u002F\u002F true  (loose — they're \"equal absences\")\nnull === undefined  \u002F\u002F false (different types)\n```\n",{"id":44,"difficulty":14,"q":45,"a":46},"typeof-array","How do you reliably check if a value is an array?","Use **`Array.isArray(value)`**. You can't use `typeof`, because arrays are\nobjects, so `typeof []` returns `'object'` — indistinguishable from a plain\nobject or `null`.\n\n```js\ntypeof []              \u002F\u002F 'object'  \u003C- useless for arrays\nArray.isArray([])      \u002F\u002F true\nArray.isArray({})      \u002F\u002F false\nArray.isArray('abc')   \u002F\u002F false\n```\n\n`Array.isArray` is also more robust than the older\n`value instanceof Array` trick, because `instanceof` **breaks across\nrealms** (e.g. an array coming from an `\u003Ciframe>` has a different `Array`\nconstructor, so `instanceof` returns `false`). `Array.isArray` works\nregardless of realm.\n",{"id":48,"difficulty":49,"q":50,"a":51},"nan","hard","Why is NaN === NaN false, and how do you test for NaN?","`NaN` (\"Not-a-Number\") is, by the IEEE-754 spec and ECMAScript, the **only\nvalue not equal to itself** — there are many distinct computations that produce\n\"not a number,\" so the standard defines all comparisons with `NaN` (including\n`NaN === NaN`) as `false`. You therefore can't detect it with `===`.\n\n```js\nNaN === NaN          \u002F\u002F false\n0 \u002F 0                \u002F\u002F NaN\nNumber('abc')        \u002F\u002F NaN\n\nNumber.isNaN(NaN)    \u002F\u002F true  reliable\nNumber.isNaN('abc')  \u002F\u002F false (no coercion — 'abc' simply isn't NaN)\n\nisNaN('abc')         \u002F\u002F true  misleading: it coerces 'abc' -> NaN first\n```\n\nUse **`Number.isNaN(value)`** (ES2015), which checks \"is this *literally* the\nNaN value.\" Avoid the **global `isNaN`**, which coerces its argument to a number\nfirst and so reports `true` for plenty of non-NaN inputs. (Another trick that\nworks: `value !== value` is `true` only for `NaN`.)\n",{"id":53,"difficulty":14,"q":54,"a":55},"object-is","What is Object.is and how does it differ from ===?","`Object.is(a, b)` is \"same-value\" equality. It behaves like `===` **except** for\ntwo edge cases: it treats `NaN` as equal to itself, and it distinguishes `+0`\nfrom `-0`.\n\n```js\nObject.is(NaN, NaN)  \u002F\u002F true   (=== gives false)\nObject.is(0, -0)     \u002F\u002F false  (=== gives true)\nObject.is(1, 1)      \u002F\u002F true\n```\n\nIt's the same algorithm React uses to decide whether state\u002Fprops changed. Use\n`===` for normal comparisons; reach for `Object.is` when those two `NaN`\u002F`-0`\nedge cases actually matter.\n",{"id":57,"difficulty":49,"q":58,"a":59},"plus-minus-zero","What is the difference between +0 and -0?","JavaScript has a signed zero: `+0` and `-0` are distinct bit patterns. They're\n**equal** under `==` and `===`, but distinguishable with `Object.is` or by\ndividing (which exposes the sign via `Infinity`).\n\n```js\n+0 === -0           \u002F\u002F true\nObject.is(+0, -0)   \u002F\u002F false\n1 \u002F +0              \u002F\u002F Infinity\n1 \u002F -0              \u002F\u002F -Infinity\n```\n\n`-0` arises from operations like `-1 * 0` or `Math.round(-0.1)`. It rarely matters,\nbut can surprise you in sign-sensitive math or when used as a Map key.\n",{"id":61,"difficulty":24,"q":62,"a":63},"typeof-function","What does typeof return for a function?","`typeof` returns `'function'` for any callable — function declarations,\nexpressions, arrows, classes, and methods. This is a special case: functions are\ntechnically objects, but `typeof` singles them out.\n\n```js\ntypeof function () {}  \u002F\u002F 'function'\ntypeof (() => {})      \u002F\u002F 'function'\ntypeof class {}        \u002F\u002F 'function' (classes are functions under the hood)\ntypeof Math.max        \u002F\u002F 'function'\ntypeof []              \u002F\u002F 'object' (arrays are NOT singled out)\n```\n\nIt's the reliable way to check \"is this callable?\" before invoking\n(`typeof cb === 'function'`).\n",{"id":65,"difficulty":14,"q":66,"a":67},"typeof-results","What are all the possible results of typeof?","`typeof` returns one of eight strings:\n\n```js\ntypeof 'a'        \u002F\u002F 'string'\ntypeof 1          \u002F\u002F 'number'\ntypeof true       \u002F\u002F 'boolean'\ntypeof undefined  \u002F\u002F 'undefined'\ntypeof 10n        \u002F\u002F 'bigint'\ntypeof Symbol()   \u002F\u002F 'symbol'\ntypeof function(){}\u002F\u002F 'function'\ntypeof {}         \u002F\u002F 'object'  (also arrays, null, dates, etc.)\n```\n\nThe famous quirk is **`typeof null === 'object'`** — a bug kept for backward\ncompatibility. Anything not in the first seven categories (including arrays and\n`null`) reports `'object'`, which is why you need `Array.isArray` and\n`=== null`.\n",{"id":69,"difficulty":49,"q":70,"a":71},"boxing","What is autoboxing of primitives?","Primitives have no methods, yet `'hi'.toUpperCase()` works because JavaScript\ntemporarily **wraps** the primitive in its object form (`String`, `Number`,\n`Boolean`), calls the method, then discards the wrapper.\n\n```js\n'hi'.length        \u002F\u002F 2 — boxed to a String object momentarily\n(5).toFixed(2)     \u002F\u002F '5.00' — boxed to Number\n\n\u002F\u002F explicit wrapper objects are an anti-pattern:\nconst n = new Number(5)\ntypeof n           \u002F\u002F 'object', not 'number'\nn === 5            \u002F\u002F false\n```\n\nNever use `new Number`\u002F`new String` — the resulting objects break `===` and are\nalways truthy (`new Boolean(false)` is truthy!). Let autoboxing happen\nimplicitly.\n",{"id":73,"difficulty":14,"q":74,"a":75},"parseint-vs-number","What is the difference between parseInt and Number?","- **`Number(x)`** converts the **entire** string to a number; any invalid\n  character makes the whole thing `NaN`. Handles decimals.\n- **`parseInt(x, radix)`** reads an **integer prefix**, stopping at the first\n  non-numeric character, and ignores the rest. Always pass the radix.\n\n```js\nNumber('42px')      \u002F\u002F NaN\nparseInt('42px', 10)\u002F\u002F 42 (parses the leading 42)\nNumber('3.14')      \u002F\u002F 3.14\nparseInt('3.14', 10)\u002F\u002F 3 (integer only)\nparseInt('0x1F', 16)\u002F\u002F 31\nNumber('')          \u002F\u002F 0  (parseInt('') is NaN)\n```\n\nUse `Number`\u002F`parseFloat` for exact full-string conversion; `parseInt` for\nextracting a leading integer (e.g. `'20px'` -> `20`).\n",{"id":77,"difficulty":49,"q":78,"a":79},"eqeq-steps","What steps does == take to coerce operands?","The abstract equality (`==`) algorithm, simplified:\n\n1. Same type -> compare like `===`.\n2. `null == undefined` -> `true` (and they equal nothing else).\n3. number vs string -> convert the **string to a number**.\n4. boolean vs anything -> convert the **boolean to a number** (`true`->1, `false`->0).\n5. object vs primitive -> convert the **object to a primitive** (`valueOf`\u002F\n   `toString`), then retry.\n\n```js\n'5' == 5      \u002F\u002F string->number: 5 == 5 -> true\ntrue == 1     \u002F\u002F boolean->number: 1 == 1 -> true\n[] == 0       \u002F\u002F [] -> '' -> 0; 0 == 0 -> true\n[] == ![]     \u002F\u002F ![] is false->0; [] -> 0; true\n```\n\nKnowing these steps explains every \"wat\" example — and is the best argument for\nalways using `===`.\n",{"id":81,"difficulty":49,"q":82,"a":83},"toprimitive","How does an object convert to a primitive (Symbol.toPrimitive)?","When an object is used where a primitive is expected, JS calls its\n`Symbol.toPrimitive` method (if present) with a **hint** (`'number'`, `'string'`,\nor `'default'`); otherwise it falls back to `valueOf` then `toString`.\n\n```js\nconst money = {\n  amount: 100,\n  [Symbol.toPrimitive](hint) {\n    return hint === 'string' ? `$${this.amount}` : this.amount\n  },\n}\n`${money}`   \u002F\u002F '$100'  (hint 'string')\nmoney + 1    \u002F\u002F 101     (hint 'default' -> number)\nmoney * 2    \u002F\u002F 200     (hint 'number')\n```\n\nThis lets you control how objects behave in concatenation, arithmetic, and\ntemplate literals.\n",{"id":85,"difficulty":14,"q":86,"a":87},"valueof-tostring","What roles do valueOf and toString play in coercion?","Without `Symbol.toPrimitive`, object-to-primitive conversion uses these two: for a\n**number** hint it tries `valueOf` first; for a **string** hint it tries\n`toString` first. Whichever returns a primitive wins.\n\n```js\nconst obj = {\n  valueOf() { return 42 },\n  toString() { return 'hello' },\n}\nobj + 1       \u002F\u002F 43      (default\u002Fnumber hint -> valueOf)\n`${obj}`      \u002F\u002F 'hello' (string hint -> toString)\nString(obj)   \u002F\u002F 'hello'\nNumber(obj)   \u002F\u002F 42\n```\n\nOverride `toString` (and sometimes `valueOf`) to make your objects coerce\nsensibly in logs and expressions.\n",{"id":89,"difficulty":24,"q":90,"a":91},"template-coercion","How does coercion work in template literals?","Template literals coerce every interpolated value to a **string** (using\n`String()` \u002F the object's `toString`). This is convenient but can produce\n`[object Object]` or `undefined`\u002F`null` text.\n\n```js\n`count: ${5}`        \u002F\u002F 'count: 5'\n`arr: ${[1, 2, 3]}`  \u002F\u002F 'arr: 1,2,3' (array toString joins with commas)\n`obj: ${ {a: 1} }`   \u002F\u002F 'obj: [object Object]'\n`val: ${null}`       \u002F\u002F 'val: null'\n```\n\nFor objects, interpolate a specific field or `JSON.stringify(obj)` rather than\nrelying on the default `[object Object]`.\n",{"id":93,"difficulty":49,"q":94,"a":95},"json-stringify","What are the edge cases of JSON.stringify?","`JSON.stringify` silently **drops or transforms** several types: `undefined`,\nfunctions, and symbols are **omitted** in objects (or become `null` in arrays);\n`NaN`\u002F`Infinity` become `null`; `BigInt` **throws**; and `Date` becomes an ISO\nstring.\n\n```js\nJSON.stringify({ a: undefined, b: () => {}, c: NaN })\n\u002F\u002F '{\"c\":null}'  — a and b dropped, NaN -> null\nJSON.stringify([undefined, function(){}, 1])\n\u002F\u002F '[null,null,1]'\nJSON.stringify(10n) \u002F\u002F TypeError: BigInt not serializable\n```\n\nIt also calls a value's `toJSON()` if present, and ignores non-enumerable\nproperties. Know these when serializing for APIs or storage.\n",{"id":97,"difficulty":14,"q":98,"a":99},"float-precision","Why does 0.1 + 0.2 not equal 0.3 in JavaScript?","All JS numbers are 64-bit IEEE-754 **doubles**. Decimal fractions like `0.1` can't\nbe represented exactly in binary, so they're stored as the nearest approximation\nand rounding errors accumulate.\n\n```js\n0.1 + 0.2            \u002F\u002F 0.30000000000000004\n0.1 + 0.2 === 0.3    \u002F\u002F false\n\n\u002F\u002F compare with a tolerance instead:\nMath.abs(0.1 + 0.2 - 0.3) \u003C Number.EPSILON \u002F\u002F true\n```\n\nFor money, work in integer **cents** or use a decimal library. Never compare\nfloats with `===`; use an epsilon tolerance.\n",{"id":101,"difficulty":14,"q":102,"a":103},"bigint","What is BigInt and how does it differ from Number?","`BigInt` represents integers of **arbitrary precision**, beyond the safe integer\nlimit of `Number` (`2^53 - 1`). Create one with an `n` suffix or `BigInt()`.\n\n```js\nNumber.MAX_SAFE_INTEGER          \u002F\u002F 9007199254740991\n9007199254740991 + 2             \u002F\u002F 9007199254740992 (wrong! lost precision)\n9007199254740991n + 2n           \u002F\u002F 9007199254740993n (exact)\n```\n\nCaveats: you **can't mix** `BigInt` and `Number` in arithmetic (`1n + 1` throws),\n`typeof 1n === 'bigint'`, and it's integer-only (no decimals). Use it for large\nIDs, timestamps in nanoseconds, and exact big-integer math.\n",{"id":105,"difficulty":14,"q":106,"a":107},"nullish-coalescing","What is the nullish coalescing operator (??)?","`a ?? b` returns `b` **only when `a` is `null` or `undefined`** — unlike `||`,\nwhich falls back on **any** falsy value (`0`, `''`, `false`). This makes `??`\ncorrect for defaults where `0`\u002F`''` are valid.\n\n```js\nconst count = 0\ncount || 10   \u002F\u002F 10  treats valid 0 as \"missing\"\ncount ?? 10   \u002F\u002F 0   only null\u002Fundefined trigger the default\n\nconst name = '' ?? 'anon' \u002F\u002F '' (empty string is kept)\n```\n\nUse `??` when only \"absent\" should trigger the fallback. You can't mix `??`\ndirectly with `&&`\u002F`||` without parentheses (a syntax error by design).\n",{"id":109,"difficulty":24,"q":110,"a":111},"optional-chaining","What is optional chaining (?.)?","`?.` short-circuits to `undefined` if the value before it is `null`\u002F`undefined`,\ninstead of throwing — letting you safely access deep properties, call maybe-\nmissing methods, and index possibly-absent values.\n\n```js\nuser?.address?.city        \u002F\u002F undefined if user or address is null\nuser?.getName?.()          \u002F\u002F calls only if getName exists\narr?.[0]                   \u002F\u002F safe index access\n```\n\nIt pairs naturally with `??`: `user?.name ?? 'anon'`. Note it stops at the first\nnullish link and only guards against `null`\u002F`undefined` — not other errors.\n",{"id":113,"difficulty":14,"q":114,"a":115},"array-equality","How do you compare two arrays or objects for equality?","`===` compares **references**, so two distinct arrays\u002Fobjects with identical\ncontents are **not** equal. You must compare contents yourself.\n\n```js\n[1, 2] === [1, 2]   \u002F\u002F false (different references)\n\n\u002F\u002F shallow array compare:\nconst eq = (a, b) => a.length === b.length && a.every((v, i) => v === b[i])\n\u002F\u002F quick (but flawed) deep compare:\nJSON.stringify(a) === JSON.stringify(b) \u002F\u002F order\u002Fundefined-sensitive\n```\n\n`JSON.stringify` works for simple data but breaks on key order, `undefined`,\nfunctions, and cycles. For robust deep equality, use a library (lodash\n`isEqual`).\n",{"id":117,"difficulty":24,"q":118,"a":119},"string-number-conversion","What are the ways to convert a string to a number?","Several, with different strictness:\n\n```js\nNumber('42')     \u002F\u002F 42      (whole string; '' -> 0, '4a' -> NaN)\nparseInt('42px', 10) \u002F\u002F 42  (leading integer)\nparseFloat('3.14m') \u002F\u002F 3.14 (leading float)\n+'42'            \u002F\u002F 42      (unary plus — concise coercion)\n'42' * 1         \u002F\u002F 42      (arithmetic coercion)\n```\n\n`Number()`\u002Funary `+` are strict (invalid -> `NaN`); `parseInt`\u002F`parseFloat` are\nlenient (parse a prefix). Always validate with `Number.isNaN` afterward when the\ninput is untrusted.\n",{"id":121,"difficulty":24,"q":122,"a":123},"boolean-double-bang","What does the double-bang (!!) operator do?","`!!x` coerces any value to its **boolean** equivalent. The first `!` converts to\nthe inverted boolean, the second `!` flips it back — giving the truthiness as a\nreal `true`\u002F`false`.\n\n```js\n!!'hello'   \u002F\u002F true\n!!0         \u002F\u002F false\n!!null      \u002F\u002F false\n!![]        \u002F\u002F true  (empty array is truthy)\nBoolean('hello') \u002F\u002F true — equivalent, more explicit\n```\n\nIt's a common idiom to normalize a value to a strict boolean (e.g. before\nreturning from a predicate or storing a flag). `Boolean(x)` does the same thing\nmore readably.\n",{"id":125,"difficulty":14,"q":126,"a":127},"symbol","What is a Symbol and what is it used for?","A `Symbol` is a **unique, immutable** primitive, mainly used as **non-colliding\nobject keys**. Every `Symbol()` is distinct, even with the same description.\n\n```js\nconst id = Symbol('id')\nconst obj = { [id]: 123 }\nobj[id]              \u002F\u002F 123\nSymbol('x') === Symbol('x') \u002F\u002F false — always unique\n```\n\nUses: private-ish keys (not enumerable in `for...in`\u002F`JSON.stringify`), and\n**well-known symbols** that customize behavior (`Symbol.iterator`,\n`Symbol.toPrimitive`, `Symbol.asyncIterator`). `Symbol.for('k')` accesses a\nshared global registry.\n",{"id":129,"difficulty":49,"q":130,"a":131},"array-coercion","How do arrays coerce to primitives?","An array's `toString` joins its elements with commas. So an empty array becomes\n`''`, a single-element array becomes that element's string, and `+` with a string\nconcatenates — leading to several classic surprises.\n\n```js\n[] + []        \u002F\u002F ''        (both -> '')\n[] + {}        \u002F\u002F '[object Object]'\n[1, 2] + [3]   \u002F\u002F '1,23'    ('1,2' + '3')\nNumber([])     \u002F\u002F 0         ('' -> 0)\nNumber([5])    \u002F\u002F 5         ('5' -> 5)\nNumber([1, 2]) \u002F\u002F NaN       ('1,2' -> NaN)\n```\n\nThese underpin the `[] == ![]` brain-teasers. The rule: array -> string (comma\njoin) -> then number if needed.\n",{"id":133,"difficulty":14,"q":134,"a":135},"nan-operations","Which operations produce NaN?","`NaN` results from **invalid or undefined mathematical operations** — converting\nnon-numeric strings, `0\u002F0`, `Infinity - Infinity`, or arithmetic on `undefined`.\nAnd `NaN` is **contagious**: any arithmetic with it yields `NaN`.\n\n```js\nNumber('abc')          \u002F\u002F NaN\n0 \u002F 0                  \u002F\u002F NaN\nMath.sqrt(-1)          \u002F\u002F NaN\nundefined + 1          \u002F\u002F NaN\nparseInt('xyz', 10)    \u002F\u002F NaN\nNaN + 5                \u002F\u002F NaN (propagates)\n```\n\nBecause it spreads, a single bad value can turn a whole calculation into `NaN` —\nguard inputs and check with `Number.isNaN`.\n",{"id":137,"difficulty":14,"q":138,"a":139},"undefined-not-defined","What is the difference between undefined and \"not defined\"?","**`undefined`** is a value: a declared variable that hasn't been assigned, or a\nmissing property. **\"Not defined\"** means the identifier doesn't exist at all —\naccessing it throws a **`ReferenceError`**.\n\n```js\nlet a\nconsole.log(a)         \u002F\u002F undefined (declared, no value)\nconsole.log(b)         \u002F\u002F ReferenceError: b is not defined\n\nconst obj = {}\nconsole.log(obj.x)     \u002F\u002F undefined (missing property, no error)\n```\n\nSo `undefined` is recoverable (it's just a value); a \"not defined\" reference is an\nerror. `typeof` is the safe way to check the latter without throwing.\n",{"id":141,"difficulty":14,"q":142,"a":143},"typeof-undeclared","Why doesn't typeof throw on an undeclared variable?","`typeof` is special-cased to **not throw** a `ReferenceError` for an undeclared\nidentifier — it returns `'undefined'`. This makes it the safe way to feature-\ndetect a global that may not exist.\n\n```js\ntypeof someUndeclaredVar  \u002F\u002F 'undefined' (no error)\nsomeUndeclaredVar         \u002F\u002F ReferenceError\n\n\u002F\u002F safe environment checks:\nif (typeof window !== 'undefined') { \u002F* browser *\u002F }\n```\n\nCaveat: this leniency does **not** apply to `let`\u002F`const` in the temporal dead\nzone — `typeof x` before a `let x` declaration still throws.\n",{"id":145,"difficulty":14,"q":146,"a":147},"immutable-primitives","What does it mean that primitives are immutable?","A primitive value itself can never be changed — operations that look like\nmutation actually create a **new** value. You can reassign the variable, but the\noriginal primitive is untouched.\n\n```js\nlet s = 'hello'\ns.toUpperCase()  \u002F\u002F 'HELLO' (a new string)\nconsole.log(s)   \u002F\u002F 'hello' (original unchanged)\ns[0] = 'J'       \u002F\u002F silently fails (or throws in strict mode)\ns = 'world'      \u002F\u002F reassigning the variable is fine\n```\n\nContrast objects\u002Farrays, which are mutable (you can change their contents in\nplace). Immutability is why primitives compare by value and are safe to share.\n",{"id":149,"difficulty":14,"q":150,"a":151},"string-comparison","How does JavaScript compare strings with \u003C and >?","Relational operators compare strings **lexicographically** by UTF-16 code unit,\ncharacter by character. This is case-sensitive (uppercase letters have lower code\npoints than lowercase) and not locale-aware.\n\n```js\n'apple' \u003C 'banana'  \u002F\u002F true\n'Z' \u003C 'a'           \u002F\u002F true  (90 \u003C 97)\n'10' \u003C '9'          \u002F\u002F true  (string compare: '1' \u003C '9')\n'10' \u003C 9            \u002F\u002F false (mixed -> numeric: 10 \u003C 9)\n```\n\nFor human-friendly, locale-aware ordering (accents, case-insensitive), use\n`a.localeCompare(b)`. Note mixed string\u002Fnumber comparisons coerce to numbers.\n",{"id":153,"difficulty":49,"q":154,"a":155},"deep-vs-shallow-equality","What is the difference between shallow and deep equality?","**Shallow** equality compares the top level: same reference, or matching primitive\nvalues \u002F first-level properties. **Deep** equality recursively compares nested\nstructures for equivalent contents.\n\n```js\nconst a = { x: { y: 1 } }\nconst b = { x: { y: 1 } }\na.x === b.x          \u002F\u002F false (different nested references)\n\u002F\u002F shallow: equal keys but nested refs differ -> not equal\n\u002F\u002F deep: recursively equal -> equal\n```\n\nReact uses shallow comparison for re-render decisions (props\u002Fstate), which is why\nmutating nested objects can be missed. Deep equality (lodash `isEqual`) is\ncostlier but compares full structure.\n",null,{"description":11},"JavaScript interview questions on primitive types, type coercion, == vs ===, truthy\u002Ffalsy values and checking types, with examples.","javascript\u002Ffundamentals\u002Fdata-types-coercion","Data Types & Coercion","Fundamentals","fundamentals","2026-06-17","vp9_844foLQtkq0K684OgyEhpivBJuIJMeUrLOlNC0k",[166,170],{"subtopic":167,"path":168,"order":169},"Variables, Scope & Hoisting","\u002Fjavascript\u002Ffundamentals\u002Fvariables-scope-hoisting",1,{"subtopic":160,"path":20,"order":12},{"path":172,"title":173},"\u002Fblog\u002Fjavascript-data-types-type-coercion","JavaScript Data Types & Type Coercion — The Complete Guide",1781808675861]