[{"data":1,"prerenderedAt":3622},["ShallowReactive",2],{"page-\u002Fjs\u002F03-operators-and-expressions":3},{"id":4,"title":5,"body":6,"description":39,"extension":3616,"meta":3617,"navigation":104,"path":3618,"seo":3619,"stem":3620,"__hash__":3621},"content\u002Fjs\u002F03-operators-and-expressions.md","03 — Operators & Expressions",{"type":7,"value":8,"toc":3580},"minimark",[9,13,200,379,577,797,974,1134,1329,1506,1705,1844,2094,2237,2434,2647,2791,2937,3065,3228,3407,3576],[10,11,5],"h1",{"id":12},"_03-operators-expressions",[14,15,17,31,91,146],"question-wrapper",{"language":16},"javascript",[18,19,21,22,26,27,30],"h3",{"id":20},"q1-what-is-the-fundamental-difference-between-and","Q1. What is the fundamental difference between ",[23,24,25],"code",{},"=="," and ",[23,28,29],{},"===","?",[32,33,34],"code-wrapper",{"language":16},[35,36,40],"pre",{"className":37,"code":38,"language":16,"meta":39,"style":39},"language-javascript shiki shiki-themes github-light github-dark","console.log(1 == \"1\");\nconsole.log(1 === \"1\");\n","",[23,41,42,73],{"__ignoreMap":39},[43,44,47,51,55,58,62,66,70],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"ssxIu","console.",[43,52,54],{"class":53},"sIsaT","log",[43,56,57],{"class":49},"(",[43,59,61],{"class":60},"snvgF","1",[43,63,65],{"class":64},"svdQ7"," ==",[43,67,69],{"class":68},"sJ6F3"," \"1\"",[43,71,72],{"class":49},");\n",[43,74,76,78,80,82,84,87,89],{"class":45,"line":75},2,[43,77,50],{"class":49},[43,79,54],{"class":53},[43,81,57],{"class":49},[43,83,61],{"class":60},[43,85,86],{"class":64}," ===",[43,88,69],{"class":68},[43,90,72],{"class":49},[92,93,96,112,124,135],"ul",{"className":94},[95],"contains-task-list",[97,98,101,106,107,109,110],"li",{"className":99},[100],"task-list-item",[102,103],"input",{"disabled":104,"type":105},true,"checkbox"," They are functionally identical; ",[23,108,29],{}," is just a stylistic alias for ",[23,111,25],{},[97,113,115,117,118,120,121,123],{"className":114},[100],[102,116],{"disabled":104,"type":105}," ",[23,119,25],{}," (loose equality) performs type coercion before comparing; ",[23,122,29],{}," (strict equality) compares both value and type with no coercion",[97,125,127,117,129,131,132,134],{"className":126},[100],[102,128],{"disabled":104,"type":105},[23,130,29],{}," performs coercion, ",[23,133,25],{}," does not",[97,136,138,117,140,142,143,145],{"className":137},[100],[102,139],{"disabled":104,"type":105},[23,141,25],{}," compares references for objects, ",[23,144,29],{}," compares values",[147,148,149,153,167],"details",{},[150,151,152],"summary",{},"Show Answer",[154,155,156,160,161,163,164,166],"p",{},[157,158,159],"strong",{},"Answer:"," B — ",[23,162,25],{}," coerces types before comparing; ",[23,165,29],{}," requires matching type and value with no coercion",[154,168,169,117,172,175,176,179,180,182,183,186,187,190,191,194,195,26,197,199],{},[157,170,171],{},"Explanation:",[23,173,174],{},"1 == \"1\""," coerces the string ",[23,177,178],{},"\"1\""," to the number ",[23,181,61],{}," before comparing, yielding ",[23,184,185],{},"true",". ",[23,188,189],{},"1 === \"1\""," compares type first — number vs. string — and since the types differ it immediately returns ",[23,192,193],{},"false"," without any coercion. Option C reverses the actual rule. Option D is unrelated to how these operators work with objects (both ",[23,196,25],{},[23,198,29],{}," compare object references identically; neither does a deep comparison).",[14,201,202,210,234,317],{"language":16},[18,203,205,206,209],{"id":204},"q2-what-does-evaluate-to","Q2. What does ",[23,207,208],{},"[] == ![]"," evaluate to?",[32,211,212],{"language":16},[35,213,215],{"className":37,"code":214,"language":16,"meta":39,"style":39},"console.log([] == ![]);\n",[23,216,217],{"__ignoreMap":39},[43,218,219,221,223,226,228,231],{"class":45,"line":46},[43,220,50],{"class":49},[43,222,54],{"class":53},[43,224,225],{"class":49},"([] ",[43,227,25],{"class":64},[43,229,230],{"class":64}," !",[43,232,233],{"class":49},"[]);\n",[92,235,237,245,296,305],{"className":236},[95],[97,238,240,117,242,244],{"className":239},[100],[102,241],{"disabled":104,"type":105},[23,243,193],{},", because an array is never equal to a boolean",[97,246,248,117,250,252,253,256,257,259,260,263,264,267,268,271,272,274,275,26,278,274,280,283,284,286,287,289,290,293,294],{"className":247},[100],[102,249],{"disabled":104,"type":105},[23,251,185],{}," — ",[23,254,255],{},"![]"," evaluates to ",[23,258,193],{}," first (since ",[23,261,262],{},"[]"," is truthy, ",[23,265,266],{},"!"," negates it), then ",[23,269,270],{},"[] == false"," coerces ",[23,273,262],{}," to ",[23,276,277],{},"\"\"",[23,279,193],{},[23,281,282],{},"0",", and ",[23,285,277],{}," coerces to ",[23,288,282],{},", so ",[23,291,292],{},"0 == 0"," is ",[23,295,185],{},[97,297,299,117,301,304],{"className":298},[100],[102,300],{"disabled":104,"type":105},[23,302,303],{},"NaN",", because arrays can't be converted to numbers",[97,306,308,117,310,313,314,316],{"className":307},[100],[102,309],{"disabled":104,"type":105},[23,311,312],{},"SyntaxError",", since ",[23,315,266],{}," cannot be applied to an array literal",[147,318,319,321,328],{},[150,320,152],{},[154,322,323,160,325,327],{},[157,324,159],{},[23,326,185],{},", through a chain of coercions",[154,329,330,117,332,335,336,338,339,293,341,343,344,346,347,349,350,352,353,355,356,358,359,352,362,364,365,352,367,369,370,372,373,375,376,378],{},[157,331,171],{},[157,333,334],{},"Debug:"," this is a famous JavaScript \"wat\" moment. Step by step: ",[23,337,262],{}," is a truthy object, so ",[23,340,255],{},[23,342,193],{},". Now the comparison is ",[23,345,270],{},". Per the ",[23,348,25],{}," algorithm, when one side is boolean, it's converted to a number first: ",[23,351,193],{}," → ",[23,354,282],{},". The other side ",[23,357,262],{}," is an object compared against a number, so it's converted via ",[23,360,361],{},"ToPrimitive",[23,363,277],{}," (empty string), then ",[23,366,277],{},[23,368,282],{}," (number coercion of an empty string). Now it's ",[23,371,292],{},", which is ",[23,374,185],{},". Every step is individually \"correct\" per spec, which is exactly what makes the combined result so counterintuitive. This is a textbook argument for avoiding ",[23,377,25],{}," (option A is the intuitive-but-wrong guess).",[14,380,381,393,473,534],{"language":16},[18,382,384,385,388,389,392],{"id":383},"q3-what-is-the-difference-between-short-circuiting-and-how-does-it-affect-side-effects","Q3. What is the difference between ",[23,386,387],{},"&&","\u002F",[23,390,391],{},"||"," short-circuiting and how does it affect side effects?",[32,394,395],{"language":16},[35,396,398],{"className":37,"code":397,"language":16,"meta":39,"style":39},"function logAndReturn(val) {\n  console.log(\"called with\", val);\n  return val;\n}\nconst result = false && logAndReturn(1);\n",[23,399,400,417,432,441,447],{"__ignoreMap":39},[43,401,402,405,408,410,414],{"class":45,"line":46},[43,403,404],{"class":64},"function",[43,406,407],{"class":53}," logAndReturn",[43,409,57],{"class":49},[43,411,413],{"class":412},"sCrzJ","val",[43,415,416],{"class":49},") {\n",[43,418,419,422,424,426,429],{"class":45,"line":75},[43,420,421],{"class":49},"  console.",[43,423,54],{"class":53},[43,425,57],{"class":49},[43,427,428],{"class":68},"\"called with\"",[43,430,431],{"class":49},", val);\n",[43,433,435,438],{"class":45,"line":434},3,[43,436,437],{"class":64},"  return",[43,439,440],{"class":49}," val;\n",[43,442,444],{"class":45,"line":443},4,[43,445,446],{"class":49},"}\n",[43,448,450,453,456,459,462,465,467,469,471],{"class":45,"line":449},5,[43,451,452],{"class":64},"const",[43,454,455],{"class":60}," result",[43,457,458],{"class":64}," =",[43,460,461],{"class":60}," false",[43,463,464],{"class":64}," &&",[43,466,407],{"class":53},[43,468,57],{"class":49},[43,470,61],{"class":60},[43,472,72],{"class":49},[92,474,476,485,508,521],{"className":475},[95],[97,477,479,117,481,484],{"className":478},[100],[102,480],{"disabled":104,"type":105},[23,482,483],{},"logAndReturn(1)"," is always called regardless of the left operand",[97,486,488,117,490,492,493,495,496,498,499,502,503,293,506],{"className":487},[100],[102,489],{"disabled":104,"type":105},[23,491,387],{}," only evaluates the right operand if the left is truthy; since ",[23,494,193],{}," is falsy, ",[23,497,483],{}," is never called, and ",[23,500,501],{},"console.log"," never runs — ",[23,504,505],{},"result",[23,507,193],{},[97,509,511,513,514,517,518,520],{"className":510},[100],[102,512],{"disabled":104,"type":105}," This throws a ",[23,515,516],{},"TypeError"," because ",[23,519,387],{}," requires both operands to be booleans",[97,522,524,117,526,293,528,530,531,533],{"className":523},[100],[102,525],{"disabled":104,"type":105},[23,527,505],{},[23,529,61],{},", because ",[23,532,387],{}," always evaluates to the last operand",[147,535,536,538,545],{},[150,537,152],{},[154,539,540,160,542,544],{},[157,541,159],{},[23,543,387],{}," short-circuits on a falsy left operand, so the right side is never evaluated",[154,546,547,117,549,551,552,554,555,495,557,559,560,293,562,564,565,567,568,571,572,388,574,576],{},[157,548,171],{},[23,550,387],{}," only evaluates its right-hand operand if the left is truthy (it \"short-circuits\" otherwise); ",[23,553,391],{}," is the mirror — it skips the right side once the left is truthy. Since ",[23,556,193],{},[23,558,483],{}," is never invoked at all — no log line prints, and ",[23,561,505],{},[23,563,193],{}," (the value of the left operand, not a boolean cast of it). ",[157,566,334],{}," relying on short-circuiting for side effects (e.g., ",[23,569,570],{},"isLoggedIn && trackEvent()",") is idiomatic but can silently skip important calls if the guard condition is wrong — worth being deliberate about. Option D is a common misconception; ",[23,573,387],{},[23,575,391],{}," return one of the actual operand values, not necessarily a boolean.",[14,578,579,589,641,726],{"language":16},[18,580,582,583,586,587,30],{"id":581},"q4-what-does-the-nullish-coalescing-operator-do-differently-from","Q4. What does the nullish coalescing operator ",[23,584,585],{},"??"," do differently from ",[23,588,391],{},[32,590,591],{"language":16},[35,592,594],{"className":37,"code":593,"language":16,"meta":39,"style":39},"const count = 0;\nconsole.log(count || 10);\nconsole.log(count ?? 10);\n",[23,595,596,611,627],{"__ignoreMap":39},[43,597,598,600,603,605,608],{"class":45,"line":46},[43,599,452],{"class":64},[43,601,602],{"class":60}," count",[43,604,458],{"class":64},[43,606,607],{"class":60}," 0",[43,609,610],{"class":49},";\n",[43,612,613,615,617,620,622,625],{"class":45,"line":75},[43,614,50],{"class":49},[43,616,54],{"class":53},[43,618,619],{"class":49},"(count ",[43,621,391],{"class":64},[43,623,624],{"class":60}," 10",[43,626,72],{"class":49},[43,628,629,631,633,635,637,639],{"class":45,"line":434},[43,630,50],{"class":49},[43,632,54],{"class":53},[43,634,619],{"class":49},[43,636,585],{"class":64},[43,638,624],{"class":60},[43,640,72],{"class":49},[92,642,644,650,694,711],{"className":643},[95],[97,645,647,649],{"className":646},[100],[102,648],{"disabled":104,"type":105}," They behave identically in all cases",[97,651,653,117,655,657,658,660,661,660,663,660,665,660,667,660,670,673,674,676,677,679,680,682,683,686,687,689,690,693],{"className":652},[100],[102,654],{"disabled":104,"type":105},[23,656,391],{}," returns the right operand if the left is any falsy value (",[23,659,282],{},", ",[23,662,277],{},[23,664,303],{},[23,666,193],{},[23,668,669],{},"null",[23,671,672],{},"undefined","); ",[23,675,585],{}," only returns the right operand if the left is specifically ",[23,678,669],{}," or ",[23,681,672],{}," — so ",[23,684,685],{},"count || 10"," wrongly overrides a legitimate ",[23,688,282],{},", while ",[23,691,692],{},"count ?? 10"," correctly preserves it",[97,695,697,117,699,701,702,704,705,707,708],{"className":696},[100],[102,698],{"disabled":104,"type":105},[23,700,585],{}," treats ",[23,703,282],{}," the same as ",[23,706,669],{},", so both log ",[23,709,710],{},"10",[97,712,714,117,716,718,719,388,721,283,723,725],{"className":713},[100],[102,715],{"disabled":104,"type":105},[23,717,391],{}," only checks for ",[23,720,669],{},[23,722,672],{},[23,724,585],{}," checks all falsy values — the reverse of the truth",[147,727,728,730,744],{},[150,729,152],{},[154,731,732,160,734,736,737,739,740,388,742],{},[157,733,159],{},[23,735,391],{}," falls back on any falsy value; ",[23,738,585],{}," only falls back on ",[23,741,669],{},[23,743,672],{},[154,745,746,117,748,750,751,753,754,757,758,760,761,530,764,766,767,770,771,773,774,776,777,779,780,782,783,785,786,788,789,791,792,785,794,796],{},[157,747,171],{},[157,749,334],{}," this is one of the most common real-world bugs ",[23,752,585],{}," (ES2020) was introduced to fix: ",[23,755,756],{},"someConfig.retries || 5"," silently replaces a deliberately-set ",[23,759,282],{}," retries value with the default ",[23,762,763],{},"5",[23,765,282],{}," is falsy. ",[23,768,769],{},"someConfig.retries ?? 5"," correctly keeps ",[23,772,282],{}," since ",[23,775,282],{}," is neither ",[23,778,669],{}," nor ",[23,781,672],{},". So here, ",[23,784,685],{}," logs ",[23,787,710],{}," (wrong, loses the real ",[23,790,282],{},"), while ",[23,793,692],{},[23,795,282],{}," (correct). Option C and D invert or misstate the actual distinction.",[14,798,799,811,853,912],{"language":16},[18,800,802,803,806,807,679,809,30],{"id":801},"q5-what-does-optional-chaining-do-when-the-left-hand-side-is-null-or-undefined","Q5. What does optional chaining ",[23,804,805],{},"?."," do when the left-hand side is ",[23,808,669],{},[23,810,672],{},[32,812,813],{"language":16},[35,814,816],{"className":37,"code":815,"language":16,"meta":39,"style":39},"const user = { profile: null };\nconsole.log(user.profile?.bio);\nconsole.log(user.profile.bio);\n",[23,817,818,835,844],{"__ignoreMap":39},[43,819,820,822,825,827,830,832],{"class":45,"line":46},[43,821,452],{"class":64},[43,823,824],{"class":60}," user",[43,826,458],{"class":64},[43,828,829],{"class":49}," { profile: ",[43,831,669],{"class":60},[43,833,834],{"class":49}," };\n",[43,836,837,839,841],{"class":45,"line":75},[43,838,50],{"class":49},[43,840,54],{"class":53},[43,842,843],{"class":49},"(user.profile?.bio);\n",[43,845,846,848,850],{"class":45,"line":434},[43,847,50],{"class":49},[43,849,54],{"class":53},[43,851,852],{"class":49},"(user.profile.bio);\n",[92,854,856,862,890,903],{"className":855},[95],[97,857,859,861],{"className":858},[100],[102,860],{"disabled":104,"type":105}," Both lines throw the same error",[97,863,865,117,867,870,871,873,874,293,877,879,880,883,884,886,887],{"className":864},[100],[102,866],{"disabled":104,"type":105},[23,868,869],{},"user.profile?.bio"," short-circuits and returns ",[23,872,672],{}," without throwing, since ",[23,875,876],{},"user.profile",[23,878,669],{},"; ",[23,881,882],{},"user.profile.bio"," (no ",[23,885,805],{},") throws ",[23,888,889],{},"TypeError: Cannot read properties of null (reading 'bio')",[97,891,893,117,895,897,898,900,901],{"className":892},[100],[102,894],{"disabled":104,"type":105},[23,896,869],{}," throws, but ",[23,899,882],{}," returns ",[23,902,672],{},[97,904,906,908,909,911],{"className":905},[100],[102,907],{"disabled":104,"type":105}," Both lines return ",[23,910,672],{}," safely, since JavaScript never throws on property access",[147,913,914,916,931],{},[150,915,152],{},[154,917,918,160,920,922,923,925,926,388,928,930],{},[157,919,159],{},[23,921,805],{}," short-circuits to ",[23,924,672],{}," on ",[23,927,669],{},[23,929,672],{},"; plain access throws",[154,932,933,935,936,679,938,940,941,943,944,946,947,925,950,952,953,313,955,957,958,961,962,964,965,968,969,26,971,973],{},[157,934,171],{}," Optional chaining checks the left side before attempting property access — if it's ",[23,937,669],{},[23,939,672],{},", the entire chain short-circuits and evaluates to ",[23,942,672],{}," immediately, skipping the rest of the expression. Without ",[23,945,805],{},", accessing ",[23,948,949],{},".bio",[23,951,669],{}," throws a ",[23,954,516],{},[23,956,669],{}," has no properties. ",[157,959,960],{},"Safety:"," the fix for the second line's error is exactly to add ",[23,963,805],{},", or to explicitly check ",[23,966,967],{},"user.profile !== null"," first. Option D falsely claims JS never throws on property access — it does, for both ",[23,970,669],{},[23,972,672],{},".",[14,975,976,980,1037,1078],{"language":16},[18,977,979],{"id":978},"q6-what-is-the-correct-operator-precedence-outcome-here","Q6. What is the correct operator precedence outcome here?",[32,981,982],{"language":16},[35,983,985],{"className":37,"code":984,"language":16,"meta":39,"style":39},"console.log(2 + 3 * 4);\nconsole.log((2 + 3) * 4);\n",[23,986,987,1012],{"__ignoreMap":39},[43,988,989,991,993,995,998,1001,1004,1007,1010],{"class":45,"line":46},[43,990,50],{"class":49},[43,992,54],{"class":53},[43,994,57],{"class":49},[43,996,997],{"class":60},"2",[43,999,1000],{"class":64}," +",[43,1002,1003],{"class":60}," 3",[43,1005,1006],{"class":64}," *",[43,1008,1009],{"class":60}," 4",[43,1011,72],{"class":49},[43,1013,1014,1016,1018,1021,1023,1025,1027,1030,1033,1035],{"class":45,"line":75},[43,1015,50],{"class":49},[43,1017,54],{"class":53},[43,1019,1020],{"class":49},"((",[43,1022,997],{"class":60},[43,1024,1000],{"class":64},[43,1026,1003],{"class":60},[43,1028,1029],{"class":49},") ",[43,1031,1032],{"class":64},"*",[43,1034,1009],{"class":60},[43,1036,72],{"class":49},[92,1038,1040,1050,1060,1069],{"className":1039},[95],[97,1041,1043,117,1045,26,1048],{"className":1042},[100],[102,1044],{"disabled":104,"type":105},[23,1046,1047],{},"20",[23,1049,1047],{},[97,1051,1053,117,1055,26,1058],{"className":1052},[100],[102,1054],{"disabled":104,"type":105},[23,1056,1057],{},"14",[23,1059,1047],{},[97,1061,1063,117,1065,26,1067],{"className":1062},[100],[102,1064],{"disabled":104,"type":105},[23,1066,1047],{},[23,1068,1057],{},[97,1070,1072,117,1074,26,1076],{"className":1071},[100],[102,1073],{"disabled":104,"type":105},[23,1075,1057],{},[23,1077,1057],{},[147,1079,1080,1082,1090],{},[150,1081,152],{},[154,1083,1084,160,1086,26,1088],{},[157,1085,159],{},[23,1087,1057],{},[23,1089,1047],{},[154,1091,1092,117,1094,1096,1097,289,1100,1103,1104,1107,1108,1111,1112,1115,1116,1119,1120,1122,1123,1125,1126,1129,1130,1133],{},[157,1093,171],{},[23,1095,1032],{}," has higher precedence than ",[23,1098,1099],{},"+",[23,1101,1102],{},"2 + 3 * 4"," computes ",[23,1105,1106],{},"3 * 4 = 12"," first, then ",[23,1109,1110],{},"2 + 12 = 14",". Parentheses override natural precedence, so ",[23,1113,1114],{},"(2 + 3) * 4"," forces ",[23,1117,1118],{},"5 * 4 = 20",". This is standard math-like precedence, but it's worth internalizing because JavaScript has many more operators with less intuitive precedence than arithmetic (e.g., where does ",[23,1121,585],{}," sit relative to ",[23,1124,391],{},", or ",[23,1127,1128],{},"typeof"," relative to ",[23,1131,1132],{},"**",").",[14,1135,1136,1147,1197,1264],{"language":16},[18,1137,1139,1140,1142,1143,1146],{"id":1138},"q7-what-does-associativity-determine-and-how-does-exponentiation-differ-from-subtraction-in-this-regard","Q7. What does associativity determine, and how does ",[23,1141,1132],{}," (exponentiation) differ from ",[23,1144,1145],{},"-"," (subtraction) in this regard?",[32,1148,1149],{"language":16},[35,1150,1152],{"className":37,"code":1151,"language":16,"meta":39,"style":39},"console.log(2 ** 3 ** 2);\nconsole.log(10 - 3 - 2);\n",[23,1153,1154,1176],{"__ignoreMap":39},[43,1155,1156,1158,1160,1162,1164,1167,1169,1171,1174],{"class":45,"line":46},[43,1157,50],{"class":49},[43,1159,54],{"class":53},[43,1161,57],{"class":49},[43,1163,997],{"class":60},[43,1165,1166],{"class":64}," **",[43,1168,1003],{"class":60},[43,1170,1166],{"class":64},[43,1172,1173],{"class":60}," 2",[43,1175,72],{"class":49},[43,1177,1178,1180,1182,1184,1186,1189,1191,1193,1195],{"class":45,"line":75},[43,1179,50],{"class":49},[43,1181,54],{"class":53},[43,1183,57],{"class":49},[43,1185,710],{"class":60},[43,1187,1188],{"class":64}," -",[43,1190,1003],{"class":60},[43,1192,1188],{"class":64},[43,1194,1173],{"class":60},[43,1196,72],{"class":49},[92,1198,1200,1211,1238,1253],{"className":1199},[95],[97,1201,1203,1205,1206,26,1209],{"className":1202},[100],[102,1204],{"disabled":104,"type":105}," Both evaluate left-to-right: ",[23,1207,1208],{},"64",[23,1210,763],{},[97,1212,1214,117,1216,1218,1219,1222,1223,1222,1226,673,1229,1231,1232,1222,1235,1237],{"className":1213},[100],[102,1215],{"disabled":104,"type":105},[23,1217,1132],{}," is right-associative (",[23,1220,1221],{},"2 ** (3 ** 2)"," = ",[23,1224,1225],{},"2 ** 9",[23,1227,1228],{},"512",[23,1230,1145],{}," is left-associative (",[23,1233,1234],{},"(10 - 3) - 2",[23,1236,763],{},")",[97,1239,1241,117,1243,1245,1246,1248,1249,26,1251],{"className":1240},[100],[102,1242],{"disabled":104,"type":105},[23,1244,1132],{}," is left-associative like ",[23,1247,1145],{},", giving ",[23,1250,1208],{},[23,1252,763],{},[97,1254,1256,1258,1259,26,1261],{"className":1255},[100],[102,1257],{"disabled":104,"type":105}," Both are right-associative, giving ",[23,1260,1228],{},[23,1262,1263],{},"9",[147,1265,1266,1268,1280],{},[150,1267,152],{},[154,1269,1270,160,1272,1218,1274,673,1276,1231,1278,1237],{},[157,1271,159],{},[23,1273,1132],{},[23,1275,1228],{},[23,1277,1145],{},[23,1279,763],{},[154,1281,1282,1284,1285,660,1287,660,1289,660,1291,1293,1294,1297,1298,1301,1302,1304,1305,1308,1309,1312,1313,186,1316,1318,1319,1297,1322,1312,1325,1328],{},[157,1283,171],{}," Associativity determines grouping order when the same-precedence operator repeats. Most operators (",[23,1286,1145],{},[23,1288,1099],{},[23,1290,1032],{},[23,1292,388],{},") are left-associative, evaluating left to right: ",[23,1295,1296],{},"10 - 3 - 2"," groups as ",[23,1299,1300],{},"(10 - 3) - 2 = 5",". Exponentiation ",[23,1303,1132],{}," is a deliberate exception — it's right-associative, matching mathematical convention where ",[23,1306,1307],{},"2^3^2"," means ",[23,1310,1311],{},"2^(3^2)",", not ",[23,1314,1315],{},"(2^3)^2",[157,1317,334],{}," so ",[23,1320,1321],{},"2 ** 3 ** 2",[23,1323,1324],{},"2 ** (3 ** 2) = 2 ** 9 = 512",[23,1326,1327],{},"(2 ** 3) ** 2 = 64"," — a frequent trip-up for people assuming all arithmetic operators associate the same way.",[14,1330,1331,1342,1401,1445],{"language":16},[18,1332,1334,1335,388,1338,1341],{"id":1333},"q8-what-happens-when-you-compare-with-across-mixed-types-eg-strings-and-numbers","Q8. What happens when you compare with ",[23,1336,1337],{},"\u003C",[23,1339,1340],{},">"," across mixed types, e.g., strings and numbers?",[32,1343,1344],{"language":16},[35,1345,1347],{"className":37,"code":1346,"language":16,"meta":39,"style":39},"console.log(\"10\" \u003C \"9\");\nconsole.log(10 \u003C 9);\nconsole.log(\"10\" \u003C 9);\n",[23,1348,1349,1368,1385],{"__ignoreMap":39},[43,1350,1351,1353,1355,1357,1360,1363,1366],{"class":45,"line":46},[43,1352,50],{"class":49},[43,1354,54],{"class":53},[43,1356,57],{"class":49},[43,1358,1359],{"class":68},"\"10\"",[43,1361,1362],{"class":64}," \u003C",[43,1364,1365],{"class":68}," \"9\"",[43,1367,72],{"class":49},[43,1369,1370,1372,1374,1376,1378,1380,1383],{"class":45,"line":75},[43,1371,50],{"class":49},[43,1373,54],{"class":53},[43,1375,57],{"class":49},[43,1377,710],{"class":60},[43,1379,1362],{"class":64},[43,1381,1382],{"class":60}," 9",[43,1384,72],{"class":49},[43,1386,1387,1389,1391,1393,1395,1397,1399],{"class":45,"line":434},[43,1388,50],{"class":49},[43,1390,54],{"class":53},[43,1392,57],{"class":49},[43,1394,1359],{"class":68},[43,1396,1362],{"class":64},[43,1398,1382],{"class":60},[43,1400,72],{"class":49},[92,1402,1404,1415,1427,1435],{"className":1403},[95],[97,1405,1407,117,1409,660,1411,660,1413],{"className":1406},[100],[102,1408],{"disabled":104,"type":105},[23,1410,193],{},[23,1412,193],{},[23,1414,193],{},[97,1416,1418,117,1420,660,1422,660,1424,1426],{"className":1417},[100],[102,1419],{"disabled":104,"type":105},[23,1421,185],{},[23,1423,193],{},[23,1425,193],{}," — the first compares two strings lexicographically (\"1\" \u003C \"9\" character-wise), the second and third involve numeric comparison after coercion",[97,1428,1430,1432,1433],{"className":1429},[100],[102,1431],{"disabled":104,"type":105}," All three are ",[23,1434,185],{},[97,1436,1438,117,1440,1442,1443],{"className":1437},[100],[102,1439],{"disabled":104,"type":105},[23,1441,312],{},", since strings cannot be compared with ",[23,1444,1337],{},[147,1446,1447,1449,1459],{},[150,1448,152],{},[154,1450,1451,160,1453,660,1455,660,1457],{},[157,1452,159],{},[23,1454,185],{},[23,1456,193],{},[23,1458,193],{},[154,1460,1461,117,1463,1466,1467,1471,1472,1474,1475,1478,1479,1481,1482,1485,1486,186,1488,1491,1492,1494,1495,352,1497,186,1499,1501,1502,1505],{},[157,1462,171],{},[23,1464,1465],{},"\"10\" \u003C \"9\""," compares two strings ",[1468,1469,1470],"em",{},"lexicographically"," (character by character, like dictionary order), not numerically: the first character ",[23,1473,178],{}," has a lower char code than ",[23,1476,1477],{},"\"9\"",", so it's ",[23,1480,185],{}," — this is the trap, since numerically 10 is greater than 9. ",[23,1483,1484],{},"10 \u003C 9"," is a normal numeric comparison: ",[23,1487,193],{},[23,1489,1490],{},"\"10\" \u003C 9"," mixes a string and a number, so the relational operator coerces the string to a number (",[23,1493,710],{},"), giving ",[23,1496,1484],{},[23,1498,193],{},[157,1500,334],{}," relational operators only compare lexicographically when ",[1468,1503,1504],{},"both"," sides are strings; introduce any non-string operand and numeric coercion kicks in instead — an inconsistency that trips up sorting and comparison logic on stringified data (e.g., data from form inputs or JSON).",[14,1507,1508,1515,1590,1650],{"language":16},[18,1509,1511,1512,1514],{"id":1510},"q9-what-is-the-result-of-comparing-with-nan-using-relational-operators","Q9. What is the result of comparing with ",[23,1513,303],{}," using relational operators?",[32,1516,1517],{"language":16},[35,1518,1520],{"className":37,"code":1519,"language":16,"meta":39,"style":39},"console.log(NaN \u003C 1);\nconsole.log(NaN > 1);\nconsole.log(NaN \u003C= NaN);\nconsole.log(NaN == NaN);\n",[23,1521,1522,1539,1556,1574],{"__ignoreMap":39},[43,1523,1524,1526,1528,1530,1532,1534,1537],{"class":45,"line":46},[43,1525,50],{"class":49},[43,1527,54],{"class":53},[43,1529,57],{"class":49},[43,1531,303],{"class":60},[43,1533,1362],{"class":64},[43,1535,1536],{"class":60}," 1",[43,1538,72],{"class":49},[43,1540,1541,1543,1545,1547,1549,1552,1554],{"class":45,"line":75},[43,1542,50],{"class":49},[43,1544,54],{"class":53},[43,1546,57],{"class":49},[43,1548,303],{"class":60},[43,1550,1551],{"class":64}," >",[43,1553,1536],{"class":60},[43,1555,72],{"class":49},[43,1557,1558,1560,1562,1564,1566,1569,1572],{"class":45,"line":434},[43,1559,50],{"class":49},[43,1561,54],{"class":53},[43,1563,57],{"class":49},[43,1565,303],{"class":60},[43,1567,1568],{"class":64}," \u003C=",[43,1570,1571],{"class":60}," NaN",[43,1573,72],{"class":49},[43,1575,1576,1578,1580,1582,1584,1586,1588],{"class":45,"line":443},[43,1577,50],{"class":49},[43,1579,54],{"class":53},[43,1581,57],{"class":49},[43,1583,303],{"class":60},[43,1585,65],{"class":64},[43,1587,1571],{"class":60},[43,1589,72],{"class":49},[92,1591,1593,1606,1628,1641],{"className":1592},[95],[97,1594,1596,117,1598,660,1600,660,1602,660,1604],{"className":1595},[100],[102,1597],{"disabled":104,"type":105},[23,1599,185],{},[23,1601,193],{},[23,1603,185],{},[23,1605,193],{},[97,1607,1609,117,1611,660,1613,660,1615,660,1617,1619,1620,1622,1623,1625,1626],{"className":1608},[100],[102,1610],{"disabled":104,"type":105},[23,1612,193],{},[23,1614,193],{},[23,1616,193],{},[23,1618,193],{}," — every comparison involving ",[23,1621,303],{}," (including ",[23,1624,303],{}," against itself) is ",[23,1627,193],{},[97,1629,1631,117,1633,660,1635,660,1637,660,1639],{"className":1630},[100],[102,1632],{"disabled":104,"type":105},[23,1634,193],{},[23,1636,193],{},[23,1638,185],{},[23,1640,185],{},[97,1642,1644,1646,1647,1649],{"className":1643},[100],[102,1645],{"disabled":104,"type":105}," Throws ",[23,1648,516],{}," on every line",[147,1651,1652,1654,1666],{},[150,1653,152],{},[154,1655,1656,160,1658,660,1660,660,1662,660,1664],{},[157,1657,159],{},[23,1659,193],{},[23,1661,193],{},[23,1663,193],{},[23,1665,193],{},[154,1667,1668,117,1670,117,1672,1674,1675,1677,1678,660,1680,660,1682,660,1685,660,1688,660,1690,1692,1693,1695,1696,1698,1699,1702,1703,973],{},[157,1669,171],{},[157,1671,334],{},[23,1673,303],{}," compares as ",[23,1676,193],{}," against literally everything, including itself, for every relational and equality operator (",[23,1679,1337],{},[23,1681,1340],{},[23,1683,1684],{},"\u003C=",[23,1686,1687],{},">=",[23,1689,25],{},[23,1691,29],{},"). This is by IEEE-754 design — ",[23,1694,303],{}," is defined as \"unordered\" relative to all values. It never throws (option D is wrong); it just always evaluates to ",[23,1697,193],{},". This is exactly why ",[23,1700,1701],{},"Number.isNaN()"," (not a comparison operator) is the only reliable way to detect ",[23,1704,303],{},[14,1706,1707,1711,1764,1804],{"language":16},[18,1708,1710],{"id":1709},"q10-what-is-the-value-of-an-empty-expression-involving-the-comma-operator","Q10. What is the value of an empty expression involving the comma operator?",[32,1712,1713],{"language":16},[35,1714,1716],{"className":37,"code":1715,"language":16,"meta":39,"style":39},"const result = (1 + 2, 3 + 4, 5 + 6);\nconsole.log(result);\n",[23,1717,1718,1755],{"__ignoreMap":39},[43,1719,1720,1722,1724,1726,1729,1731,1733,1735,1737,1740,1742,1744,1746,1748,1750,1753],{"class":45,"line":46},[43,1721,452],{"class":64},[43,1723,455],{"class":60},[43,1725,458],{"class":64},[43,1727,1728],{"class":49}," (",[43,1730,61],{"class":60},[43,1732,1000],{"class":64},[43,1734,1173],{"class":60},[43,1736,660],{"class":49},[43,1738,1739],{"class":60},"3",[43,1741,1000],{"class":64},[43,1743,1009],{"class":60},[43,1745,660],{"class":49},[43,1747,763],{"class":60},[43,1749,1000],{"class":64},[43,1751,1752],{"class":60}," 6",[43,1754,72],{"class":49},[43,1756,1757,1759,1761],{"class":45,"line":75},[43,1758,50],{"class":49},[43,1760,54],{"class":53},[43,1762,1763],{"class":49},"(result);\n",[92,1765,1767,1775,1783,1792],{"className":1766},[95],[97,1768,1770,117,1772,1774],{"className":1769},[100],[102,1771],{"disabled":104,"type":105},[23,1773,312],{}," — commas are not valid inside parentheses like this",[97,1776,1778,117,1780,1782],{"className":1777},[100],[102,1779],{"disabled":104,"type":105},[23,1781,1739],{},", the result of the first expression",[97,1784,1786,117,1788,1791],{"className":1785},[100],[102,1787],{"disabled":104,"type":105},[23,1789,1790],{},"11",", the result of the second expression",[97,1793,1795,117,1797,1799,1800,1803],{"className":1794},[100],[102,1796],{"disabled":104,"type":105},[23,1798,1790],{},", since the comma operator evaluates each operand left to right and yields the value of the ",[1468,1801,1802],{},"last"," one",[147,1805,1806,1808,1816],{},[150,1807,152],{},[154,1809,1810,1812,1813,1815],{},[157,1811,159],{}," D — ",[23,1814,1790],{},", the value of the last comma-separated expression",[154,1817,1818,1820,1821,1824,1825,1828,1829,1832,1833,1835,1836,1839,1840,1843],{},[157,1819,171],{}," The comma operator evaluates each expression in sequence (for their side effects) and yields only the final one's value. Here ",[23,1822,1823],{},"1 + 2"," (=3) and ",[23,1826,1827],{},"3 + 4"," (=7) are computed and discarded, and ",[23,1830,1831],{},"5 + 6"," (=11) becomes the expression's value, assigned to ",[23,1834,505],{},". This operator is rarely used explicitly outside of terse ",[23,1837,1838],{},"for"," loop headers (",[23,1841,1842],{},"for (let i = 0, j = 10; i \u003C j; i++, j--)",") — using it for arbitrary sequencing like this example is unusual and hurts readability, but is valid, well-defined syntax, not an error (ruling out option A).",[14,1845,1846,1853,1948,2030],{"language":16},[18,1847,1849,1850,1852],{"id":1848},"q11-what-does-the-unary-operator-do-to-a-string-operand","Q11. What does the unary ",[23,1851,1099],{}," operator do to a string operand?",[32,1854,1855],{"language":16},[35,1856,1858],{"className":37,"code":1857,"language":16,"meta":39,"style":39},"console.log(+\"42\");\nconsole.log(+\"\");\nconsole.log(+\"  \");\nconsole.log(+\"abc\");\nconsole.log(+null);\nconsole.log(+undefined);\n",[23,1859,1860,1875,1889,1904,1919,1933],{"__ignoreMap":39},[43,1861,1862,1864,1866,1868,1870,1873],{"class":45,"line":46},[43,1863,50],{"class":49},[43,1865,54],{"class":53},[43,1867,57],{"class":49},[43,1869,1099],{"class":64},[43,1871,1872],{"class":68},"\"42\"",[43,1874,72],{"class":49},[43,1876,1877,1879,1881,1883,1885,1887],{"class":45,"line":75},[43,1878,50],{"class":49},[43,1880,54],{"class":53},[43,1882,57],{"class":49},[43,1884,1099],{"class":64},[43,1886,277],{"class":68},[43,1888,72],{"class":49},[43,1890,1891,1893,1895,1897,1899,1902],{"class":45,"line":434},[43,1892,50],{"class":49},[43,1894,54],{"class":53},[43,1896,57],{"class":49},[43,1898,1099],{"class":64},[43,1900,1901],{"class":68},"\"  \"",[43,1903,72],{"class":49},[43,1905,1906,1908,1910,1912,1914,1917],{"class":45,"line":443},[43,1907,50],{"class":49},[43,1909,54],{"class":53},[43,1911,57],{"class":49},[43,1913,1099],{"class":64},[43,1915,1916],{"class":68},"\"abc\"",[43,1918,72],{"class":49},[43,1920,1921,1923,1925,1927,1929,1931],{"class":45,"line":449},[43,1922,50],{"class":49},[43,1924,54],{"class":53},[43,1926,57],{"class":49},[43,1928,1099],{"class":64},[43,1930,669],{"class":60},[43,1932,72],{"class":49},[43,1934,1936,1938,1940,1942,1944,1946],{"class":45,"line":1935},6,[43,1937,50],{"class":49},[43,1939,54],{"class":53},[43,1941,57],{"class":49},[43,1943,1099],{"class":64},[43,1945,672],{"class":60},[43,1947,72],{"class":49},[92,1949,1951,1969,2004,2022],{"className":1950},[95],[97,1952,1954,117,1956,660,1959,660,1961,660,1963,660,1965,660,1967],{"className":1953},[100],[102,1955],{"disabled":104,"type":105},[23,1957,1958],{},"42",[23,1960,303],{},[23,1962,303],{},[23,1964,303],{},[23,1966,282],{},[23,1968,303],{},[97,1970,1972,117,1974,660,1976,660,1978,660,1980,660,1982,660,1984,1986,1987,1989,1990,1992,1993,660,1995,1997,1998,283,2000,1997,2002],{"className":1971},[100],[102,1973],{"disabled":104,"type":105},[23,1975,1958],{},[23,1977,282],{},[23,1979,282],{},[23,1981,303],{},[23,1983,282],{},[23,1985,303],{}," — unary ",[23,1988,1099],{}," coerces to a number; an empty or whitespace-only string becomes ",[23,1991,282],{},", a non-numeric string becomes ",[23,1994,303],{},[23,1996,669],{}," becomes ",[23,1999,282],{},[23,2001,672],{},[23,2003,303],{},[97,2005,2007,117,2009,660,2011,660,2013,660,2015,660,2017,660,2019,2021],{"className":2006},[100],[102,2008],{"disabled":104,"type":105},[23,2010,1872],{},[23,2012,277],{},[23,2014,277],{},[23,2016,1916],{},[23,2018,669],{},[23,2020,672],{}," (no coercion happens)",[97,2023,2025,2027,2028],{"className":2024},[100],[102,2026],{"disabled":104,"type":105}," All six results are ",[23,2029,303],{},[147,2031,2032,2034,2050],{},[150,2033,152],{},[154,2035,2036,160,2038,660,2040,660,2042,660,2044,660,2046,660,2048],{},[157,2037,159],{},[23,2039,1958],{},[23,2041,282],{},[23,2043,282],{},[23,2045,303],{},[23,2047,282],{},[23,2049,303],{},[154,2051,2052,2054,2055,2057,2058,2061,2062,1312,2064,2066,2067,2070,2071,2073,2074,2076,2077,293,2080,2082,2083,293,2086,186,2088,2090,2091,2093],{},[157,2053,171],{}," Unary ",[23,2056,1099],{}," is a common idiom for explicit numeric coercion. Strings are converted via ",[23,2059,2060],{},"Number()"," rules: numeric-looking strings parse normally, and — the gotcha — an empty string or a string of only whitespace converts to ",[23,2063,282],{},[23,2065,303],{}," (since ",[23,2068,2069],{},"Number(\"\")"," trims to nothing and treats that as zero). A truly non-numeric string like ",[23,2072,1916],{}," produces ",[23,2075,303],{},". Separately, ",[23,2078,2079],{},"Number(null)",[23,2081,282],{}," (a well-known inconsistency), while ",[23,2084,2085],{},"Number(undefined)",[23,2087,303],{},[157,2089,334],{}," the empty-string-becomes-zero behavior is a frequent source of validation bugs when checking \"is this field a number\" using truthiness or unary ",[23,2092,1099],{}," alone.",[14,2095,2096,2104,2144,2196],{"language":16},[18,2097,2099,2100,2103],{"id":2098},"q12-in-a-b-c-what-happens","Q12. In ",[23,2101,2102],{},"a ?? b || c",", what happens?",[32,2105,2106],{"language":16},[35,2107,2109],{"className":37,"code":2108,"language":16,"meta":39,"style":39},"const a = null;\nconsole.log(a ?? b || c);\n",[23,2110,2111,2125],{"__ignoreMap":39},[43,2112,2113,2115,2118,2120,2123],{"class":45,"line":46},[43,2114,452],{"class":64},[43,2116,2117],{"class":60}," a",[43,2119,458],{"class":64},[43,2121,2122],{"class":60}," null",[43,2124,610],{"class":49},[43,2126,2127,2129,2131,2134,2136,2139,2141],{"class":45,"line":75},[43,2128,50],{"class":49},[43,2130,54],{"class":53},[43,2132,2133],{"class":49},"(a ",[43,2135,585],{"class":64},[43,2137,2138],{"class":49}," b ",[43,2140,391],{"class":64},[43,2142,2143],{"class":49}," c);\n",[92,2145,2147,2158,2176,2186],{"className":2146},[95],[97,2148,2150,2152,2153,26,2155,2157],{"className":2149},[100],[102,2151],{"disabled":104,"type":105}," It evaluates fine, left to right, treating ",[23,2154,585],{},[23,2156,391],{}," as equal precedence",[97,2159,2161,2163,2164,2166,2167,2169,2170,2172,2173,2175],{"className":2160},[100],[102,2162],{"disabled":104,"type":105}," It throws a ",[23,2165,312],{}," — mixing ",[23,2168,585],{}," directly with ",[23,2171,391],{}," (or ",[23,2174,387],{},") without explicit parentheses is a syntax error, precisely because their relative precedence\u002Fassociativity is ambiguous and disallowed by the spec",[97,2177,2179,117,2181,2183,2184],{"className":2178},[100],[102,2180],{"disabled":104,"type":105},[23,2182,585],{}," always takes precedence and short-circuits, ignoring ",[23,2185,391],{},[97,2187,2189,117,2191,2193,2194],{"className":2188},[100],[102,2190],{"disabled":104,"type":105},[23,2192,391],{}," always takes precedence over ",[23,2195,585],{},[147,2197,2198,2200,2215],{},[150,2199,152],{},[154,2201,2202,2204,2205,2207,2208,388,2210,2212,2213],{},[157,2203,159],{}," B — Mixing ",[23,2206,585],{}," with ",[23,2209,391],{},[23,2211,387],{}," without parentheses is a ",[23,2214,312],{},[154,2216,2217,117,2219,2221,2222,2224,2225,679,2227,2229,2230,679,2233,2236],{},[157,2218,171],{},[157,2220,960],{}," unlike most operators, which have a well-defined relative precedence, the spec explicitly forbids writing ",[23,2223,585],{}," directly adjacent to ",[23,2226,391],{},[23,2228,387],{}," without parentheses (",[23,2231,2232],{},"(a ?? b) || c",[23,2234,2235],{},"a ?? (b || c)","), because their intended grouping is genuinely ambiguous and error-prone to guess. This is a deliberate design choice to force developers to be explicit rather than rely on a precedence table few people would remember correctly. Options C and D each assume an implicit ordering that the language intentionally refuses to define without parentheses.",[14,2238,2239,2243,2303,2371],{"language":16},[18,2240,2242],{"id":2241},"q13-what-is-the-output-of-this-logical-assignment-operator-usage","Q13. What is the output of this logical assignment operator usage?",[32,2244,2245],{"language":16},[35,2246,2248],{"className":37,"code":2247,"language":16,"meta":39,"style":39},"let config = { timeout: 0 };\nconfig.timeout ??= 3000;\nconfig.retries ||= 5;\nconsole.log(config);\n",[23,2249,2250,2268,2281,2294],{"__ignoreMap":39},[43,2251,2252,2255,2258,2261,2264,2266],{"class":45,"line":46},[43,2253,2254],{"class":64},"let",[43,2256,2257],{"class":49}," config ",[43,2259,2260],{"class":64},"=",[43,2262,2263],{"class":49}," { timeout: ",[43,2265,282],{"class":60},[43,2267,834],{"class":49},[43,2269,2270,2273,2276,2279],{"class":45,"line":75},[43,2271,2272],{"class":49},"config.timeout ",[43,2274,2275],{"class":64},"??=",[43,2277,2278],{"class":60}," 3000",[43,2280,610],{"class":49},[43,2282,2283,2286,2289,2292],{"class":45,"line":434},[43,2284,2285],{"class":49},"config.retries ",[43,2287,2288],{"class":64},"||=",[43,2290,2291],{"class":60}," 5",[43,2293,610],{"class":49},[43,2295,2296,2298,2300],{"class":45,"line":443},[43,2297,50],{"class":49},[43,2299,54],{"class":53},[43,2301,2302],{"class":49},"(config);\n",[92,2304,2306,2318,2352,2363],{"className":2305},[95],[97,2307,2309,117,2311,2314,2315,2317],{"className":2308},[100],[102,2310],{"disabled":104,"type":105},[23,2312,2313],{},"{ timeout: 3000, retries: 5 }"," — both operators overwrite because ",[23,2316,282],{}," is falsy",[97,2319,2321,117,2323,252,2326,2328,2329,388,2331,2333,2334,2337,2338,673,2340,2342,2343,2346,2347,2349,2350,1237],{"className":2320},[100],[102,2322],{"disabled":104,"type":105},[23,2324,2325],{},"{ timeout: 0, retries: 5 }",[23,2327,2275],{}," only assigns if the left is ",[23,2330,669],{},[23,2332,672],{}," (so ",[23,2335,2336],{},"timeout"," stays ",[23,2339,282],{},[23,2341,2288],{}," assigns if the left is falsy or missing (so ",[23,2344,2345],{},"retries",", being ",[23,2348,672],{},", becomes ",[23,2351,763],{},[97,2353,2355,117,2357,252,2360,2362],{"className":2354},[100],[102,2356],{"disabled":104,"type":105},[23,2358,2359],{},"{ timeout: 0 }",[23,2361,2345],{}," is left untouched since it was never declared",[97,2364,2366,117,2368,2370],{"className":2365},[100],[102,2367],{"disabled":104,"type":105},[23,2369,516],{},", since you can't use logical assignment on object properties",[147,2372,2373,2375,2381],{},[150,2374,152],{},[154,2376,2377,160,2379],{},[157,2378,159],{},[23,2380,2325],{},[154,2382,2383,117,2385,2387,2388,2391,2392,388,2394,2396,2397,293,2399,2401,2402,2404,2405,2407,2408,2410,2411,2413,2414,186,2416,117,2419,2421,2422,2424,2425,2427,2428,2430,2431,2433],{},[157,2384,171],{},[23,2386,2275],{}," (ES2021) is shorthand for ",[23,2389,2390],{},"x ?? (x = y)"," — it only assigns when the current value is ",[23,2393,669],{},[23,2395,672],{},". Since ",[23,2398,2336],{},[23,2400,282],{}," (not nullish), ",[23,2403,2275],{}," leaves it untouched. ",[23,2406,2345],{}," doesn't exist yet, so accessing it is ",[23,2409,672],{},", which is both nullish and falsy — ",[23,2412,2288],{}," assigns ",[23,2415,763],{},[157,2417,2418],{},"Idiom:",[23,2420,2275],{}," is the safer choice specifically for numeric defaults like ",[23,2423,2336],{}," where ",[23,2426,282],{}," is a meaningful, valid value that shouldn't be clobbered — mirroring the ",[23,2429,585],{}," vs ",[23,2432,391],{}," distinction from Q4.",[14,2435,2436,2443,2509,2579],{"language":16},[18,2437,2439,2440,2442],{"id":2438},"q14-what-does-typeof-return-for-these-edge-case-expressions","Q14. What does ",[23,2441,1128],{}," return for these edge-case expressions?",[32,2444,2445],{"language":16},[35,2446,2448],{"className":37,"code":2447,"language":16,"meta":39,"style":39},"console.log(typeof (1 \u003C 2));\nconsole.log(typeof typeof 1);\nconsole.log(typeof (1, \"a\"));\n",[23,2449,2450,2471,2488],{"__ignoreMap":39},[43,2451,2452,2454,2456,2458,2460,2462,2464,2466,2468],{"class":45,"line":46},[43,2453,50],{"class":49},[43,2455,54],{"class":53},[43,2457,57],{"class":49},[43,2459,1128],{"class":64},[43,2461,1728],{"class":49},[43,2463,61],{"class":60},[43,2465,1362],{"class":64},[43,2467,1173],{"class":60},[43,2469,2470],{"class":49},"));\n",[43,2472,2473,2475,2477,2479,2481,2484,2486],{"class":45,"line":75},[43,2474,50],{"class":49},[43,2476,54],{"class":53},[43,2478,57],{"class":49},[43,2480,1128],{"class":64},[43,2482,2483],{"class":64}," typeof",[43,2485,1536],{"class":60},[43,2487,72],{"class":49},[43,2489,2490,2492,2494,2496,2498,2500,2502,2504,2507],{"class":45,"line":434},[43,2491,50],{"class":49},[43,2493,54],{"class":53},[43,2495,57],{"class":49},[43,2497,1128],{"class":64},[43,2499,1728],{"class":49},[43,2501,61],{"class":60},[43,2503,660],{"class":49},[43,2505,2506],{"class":68},"\"a\"",[43,2508,2470],{"class":49},[92,2510,2512,2526,2557,2568],{"className":2511},[95],[97,2513,2515,117,2517,660,2520,660,2523],{"className":2514},[100],[102,2516],{"disabled":104,"type":105},[23,2518,2519],{},"\"boolean\"",[23,2521,2522],{},"\"number\"",[23,2524,2525],{},"\"string\"",[97,2527,2529,117,2531,660,2533,660,2535,252,2537,2539,2540,879,2542,2545,2546,517,2548,2550,2551,2553,2554,2556],{"className":2528},[100],[102,2530],{"disabled":104,"type":105},[23,2532,2519],{},[23,2534,2525],{},[23,2536,2525],{},[23,2538,1128],{}," on a comparison gives ",[23,2541,2519],{},[23,2543,2544],{},"typeof typeof x"," is always ",[23,2547,2525],{},[23,2549,1128],{}," itself always returns a string, and the comma operator yields its last operand (",[23,2552,2506],{},") before ",[23,2555,1128],{}," runs on it",[97,2558,2560,117,2562,660,2564,660,2566],{"className":2559},[100],[102,2561],{"disabled":104,"type":105},[23,2563,2519],{},[23,2565,2522],{},[23,2567,2522],{},[97,2569,2571,117,2573,2575,2576,2578],{"className":2570},[100],[102,2572],{"disabled":104,"type":105},[23,2574,312],{}," on the last line, since ",[23,2577,1128],{}," cannot be applied to a comma expression",[147,2580,2581,2583,2593],{},[150,2582,152],{},[154,2584,2585,160,2587,660,2589,660,2591],{},[157,2586,159],{},[23,2588,2519],{},[23,2590,2525],{},[23,2592,2525],{},[154,2594,2595,117,2597,2600,2601,289,2603,2605,2606,186,2608,2611,2612,2614,2615,274,2617,2620,2621,2623,2624,2626,2627,2629,2630,256,2633,2635,2636,293,2639,2641,2642,2644,2645,973],{},[157,2596,171],{},[23,2598,2599],{},"1 \u003C 2"," evaluates to the boolean ",[23,2602,185],{},[23,2604,1128],{}," gives ",[23,2607,2519],{},[23,2609,2610],{},"typeof 1"," evaluates to the string ",[23,2613,2522],{},"; applying ",[23,2616,1128],{},[1468,2618,2619],{},"that"," result (a string) gives ",[23,2622,2525],{}," — a fun consequence of ",[23,2625,1128],{}," always producing a string value, so nesting it twice always ends in ",[23,2628,2525],{}," regardless of the original operand. The comma expression ",[23,2631,2632],{},"(1, \"a\")",[23,2634,2506],{}," (per Q10's rule), and ",[23,2637,2638],{},"typeof \"a\"",[23,2640,2525],{},". Option D wrongly assumes ",[23,2643,1128],{}," can't handle a parenthesized comma expression — it's just a normal expression to ",[23,2646,1128],{},[14,2648,2649,2665,2704,2755],{"language":16},[18,2650,2652,2653,388,2655,2658,2659,388,2661,2664],{"id":2651},"q15-what-is-the-idiomatic-reason-to-prefer-over-in-production-code","Q15. What is the idiomatic reason to prefer ",[23,2654,29],{},[23,2656,2657],{},"!=="," over ",[23,2660,25],{},[23,2662,2663],{},"!="," in production code?",[32,2666,2667],{"language":16},[35,2668,2670],{"className":37,"code":2669,"language":16,"meta":39,"style":39},"function isAdmin(role) {\n  return role == \"admin\";\n}\n",[23,2671,2672,2686,2700],{"__ignoreMap":39},[43,2673,2674,2676,2679,2681,2684],{"class":45,"line":46},[43,2675,404],{"class":64},[43,2677,2678],{"class":53}," isAdmin",[43,2680,57],{"class":49},[43,2682,2683],{"class":412},"role",[43,2685,416],{"class":49},[43,2687,2688,2690,2693,2695,2698],{"class":45,"line":75},[43,2689,437],{"class":64},[43,2691,2692],{"class":49}," role ",[43,2694,25],{"class":64},[43,2696,2697],{"class":68}," \"admin\"",[43,2699,610],{"class":49},[43,2701,2702],{"class":45,"line":434},[43,2703,446],{"class":49},[92,2705,2707,2715,2735,2749],{"className":2706},[95],[97,2708,2710,117,2712,2714],{"className":2709},[100],[102,2711],{"disabled":104,"type":105},[23,2713,25],{}," is deprecated and will be removed from future ECMAScript versions",[97,2716,2718,117,2720,2722,2723,2725,2726,2728,2729,2731,2732],{"className":2717},[100],[102,2719],{"disabled":104,"type":105},[23,2721,29],{}," avoids the unpredictable, hard-to-audit coercion rules of ",[23,2724,25],{}," (as seen with ",[23,2727,270],{}," and similar cases), making comparisons behave exactly as written; ",[23,2730,25],{}," should be reserved for the few well-understood idioms like ",[23,2733,2734],{},"x == null",[97,2736,2738,117,2740,2742,2743,2745,2746,2748],{"className":2737},[100],[102,2739],{"disabled":104,"type":105},[23,2741,25],{}," is slower at runtime than ",[23,2744,29],{}," in all engines, so ",[23,2747,29],{}," is purely a performance optimization",[97,2750,2752,2754],{"className":2751},[100],[102,2753],{"disabled":104,"type":105}," There's no real-world difference; the choice is purely stylistic with zero behavioral impact",[147,2756,2757,2759,2774],{},[150,2758,152],{},[154,2760,2761,160,2763,2765,2766,2768,2769,2771,2772],{},[157,2762,159],{},[23,2764,29],{}," avoids ",[23,2767,25],{},"'s unpredictable coercion; ",[23,2770,25],{}," is reserved for well-understood idioms like ",[23,2773,2734],{},[154,2775,2776,117,2778,2780,2781,2783,2784,2787,2788,2790],{},[157,2777,171],{},[157,2779,2418],{}," the core argument for ",[23,2782,29],{}," is correctness and reviewability, not performance — coercion rules like the array\u002Fboolean example from Q2 are genuinely hard to reason about at a glance, and bugs from accidental type mismatches (e.g., comparing a form input string against a numeric constant) are common. Style guides carve out ",[23,2785,2786],{},"== null"," as an accepted exception (per Q19 of the previous file) precisely because that one coercion behavior is well-known and intentional. Option A is false — ",[23,2789,25],{}," is not deprecated or going anywhere. Option C overstates and mischaracterizes the actual (in practice negligible) performance difference as the primary motivation.",[14,2792,2793,2804,2845,2894],{"language":16},[18,2794,2796,2797,660,2799,1125,2801,2803],{"id":2795},"q16-what-is-the-best-practice-way-to-write-a-conditional-default-value-assignment-when-0-or-false-might-be-legitimate-values","Q16. What is the best-practice way to write a conditional default value assignment when ",[23,2798,282],{},[23,2800,277],{},[23,2802,193],{}," might be legitimate values?",[32,2805,2806],{"language":16},[35,2807,2809],{"className":37,"code":2808,"language":16,"meta":39,"style":39},"function createUser({ retries = 3, isActive = true } = {}) {}\n",[23,2810,2811],{"__ignoreMap":39},[43,2812,2813,2815,2818,2821,2823,2825,2827,2829,2832,2834,2837,2840,2842],{"class":45,"line":46},[43,2814,404],{"class":64},[43,2816,2817],{"class":53}," createUser",[43,2819,2820],{"class":49},"({ ",[43,2822,2345],{"class":412},[43,2824,458],{"class":64},[43,2826,1003],{"class":60},[43,2828,660],{"class":49},[43,2830,2831],{"class":412},"isActive",[43,2833,458],{"class":64},[43,2835,2836],{"class":60}," true",[43,2838,2839],{"class":49}," } ",[43,2841,2260],{"class":64},[43,2843,2844],{"class":49}," {}) {}\n",[92,2846,2848,2860,2878,2888],{"className":2847},[95],[97,2849,2851,2853,2854,2856,2857],{"className":2850},[100],[102,2852],{"disabled":104,"type":105}," Always use ",[23,2855,391],{}," for defaults: ",[23,2858,2859],{},"const r = retries || 3;",[97,2861,2863,2865,2866,2658,2868,2870,2871,2873,2874,679,2876],{"className":2862},[100],[102,2864],{"disabled":104,"type":105}," Prefer default parameters (as shown) or ",[23,2867,585],{},[23,2869,391],{}," for fallback values, since both correctly distinguish \"not provided\" (",[23,2872,672],{},") from an intentionally falsy value like ",[23,2875,282],{},[23,2877,193],{},[97,2879,2881,2883,2884,2887],{"className":2880},[100],[102,2882],{"disabled":104,"type":105}," Use a ternary checking ",[23,2885,2886],{},"typeof x === \"boolean\""," for every possible falsy type individually",[97,2889,2891,2893],{"className":2890},[100],[102,2892],{"disabled":104,"type":105}," It never matters which operator is used, since defaults are rarely falsy in practice",[147,2895,2896,2898,2906],{},[150,2897,152],{},[154,2899,2900,2902,2903,2905],{},[157,2901,159],{}," B — Prefer default parameters or ",[23,2904,585],{}," since they correctly distinguish \"not provided\" from a legitimate falsy value",[154,2907,2908,117,2910,2912,2913,2916,2917,2919,2920,2923,2924,2926,2927,2929,2930,660,2932,1125,2934,2936],{},[157,2909,171],{},[157,2911,2418],{}," default parameters (as in the ",[23,2914,2915],{},"createUser"," signature) only kick in when an argument is literally ",[23,2918,672],{}," — passing ",[23,2921,2922],{},"retries: 0"," explicitly is respected, not overridden — which mirrors ",[23,2925,585],{},"'s \"nullish, not falsy\" semantics discussed in Q4. Using ",[23,2928,391],{}," for defaults, by contrast, is a common but subtly wrong pattern that silently discards deliberate falsy inputs like ",[23,2931,282],{},[23,2933,277],{},[23,2935,193],{},". Option C is technically workable but needlessly verbose compared to the built-in mechanisms designed for exactly this. Option D is wrong in practice — falsy-but-valid defaults (counts, flags, empty strings) are extremely common in real APIs.",[14,2938,2939,2948,2970,3019],{"language":16},[18,2940,2942,2943,388,2945,2947],{"id":2941},"q17-which-is-the-idiomatic-pattern-for-guarding-against-nullundefined-when-calling-a-method-that-might-not-exist","Q17. Which is the idiomatic pattern for guarding against ",[23,2944,669],{},[23,2946,672],{}," when calling a method that might not exist?",[32,2949,2950],{"language":16},[35,2951,2953],{"className":37,"code":2952,"language":16,"meta":39,"style":39},"const config = getConfig();\n",[23,2954,2955],{"__ignoreMap":39},[43,2956,2957,2959,2962,2964,2967],{"class":45,"line":46},[43,2958,452],{"class":64},[43,2960,2961],{"class":60}," config",[43,2963,458],{"class":64},[43,2965,2966],{"class":53}," getConfig",[43,2968,2969],{"class":49},"();\n",[92,2971,2973,2981,3001,3010],{"className":2972},[95],[97,2974,2976,117,2978],{"className":2975},[100],[102,2977],{"disabled":104,"type":105},[23,2979,2980],{},"config && config.onReady && config.onReady()",[97,2982,2984,117,2986,2989,2990,2992,2993,388,2995,2997,2998,3000],{"className":2983},[100],[102,2985],{"disabled":104,"type":105},[23,2987,2988],{},"config?.onReady?.()"," — optional chaining combined with the optional call syntax, which short-circuits to ",[23,2991,672],{}," at the first ",[23,2994,669],{},[23,2996,672],{}," link without throwing, and is more concise\u002Fless error-prone than manual ",[23,2999,387],{}," chains",[97,3002,3004,117,3006,3009],{"className":3003},[100],[102,3005],{"disabled":104,"type":105},[23,3007,3008],{},"if (config.onReady !== undefined) config.onReady();"," (no chaining needed)",[97,3011,3013,117,3015,3018],{"className":3012},[100],[102,3014],{"disabled":104,"type":105},[23,3016,3017],{},"try { config.onReady(); } catch (e) {}"," — swallow any resulting error",[147,3020,3021,3023,3030],{},[150,3022,152],{},[154,3024,3025,160,3027,3029],{},[157,3026,159],{},[23,3028,2988],{}," using optional chaining plus optional call syntax",[154,3031,3032,117,3034,117,3036,3039,3040,679,3043,3046,3047,3049,3050,3052,3053,388,3055,946,3057,3060,3061,3064],{},[157,3033,171],{},[157,3035,2418],{},[23,3037,3038],{},"?.()"," (optional call, part of the same ES2020 optional chaining feature) skips the call entirely if ",[23,3041,3042],{},"config",[23,3044,3045],{},"config.onReady"," is nullish, matching the intent of the older ",[23,3048,387],{},"-chain pattern (option A) but far more concisely and without repeating each property name. Option C is unsafe — if ",[23,3051,3042],{}," itself is ",[23,3054,669],{},[23,3056,672],{},[23,3058,3059],{},".onReady"," on it throws before the check even runs. Option D is a code smell: swallowing all errors silently (including genuine bugs inside ",[23,3062,3063],{},"onReady",") makes debugging much harder — the correct approach is to only guard against the specific \"doesn't exist\" case, not blanket-catch everything.",[14,3066,3067,3071,3121,3178],{"language":16},[18,3068,3070],{"id":3069},"q18-why-can-chained-optional-chaining-still-throw-in-some-cases-and-how-should-that-be-handled","Q18. Why can chained optional chaining still throw in some cases, and how should that be handled?",[32,3072,3073],{"language":16},[35,3074,3076],{"className":37,"code":3075,"language":16,"meta":39,"style":39},"const user = { getProfile: null };\nconsole.log(user.getProfile());\nconsole.log(user.getProfile?.());\n",[23,3077,3078,3093,3108],{"__ignoreMap":39},[43,3079,3080,3082,3084,3086,3089,3091],{"class":45,"line":46},[43,3081,452],{"class":64},[43,3083,824],{"class":60},[43,3085,458],{"class":64},[43,3087,3088],{"class":49}," { getProfile: ",[43,3090,669],{"class":60},[43,3092,834],{"class":49},[43,3094,3095,3097,3099,3102,3105],{"class":45,"line":75},[43,3096,50],{"class":49},[43,3098,54],{"class":53},[43,3100,3101],{"class":49},"(user.",[43,3103,3104],{"class":53},"getProfile",[43,3106,3107],{"class":49},"());\n",[43,3109,3110,3112,3114,3116,3118],{"class":45,"line":434},[43,3111,50],{"class":49},[43,3113,54],{"class":53},[43,3115,3101],{"class":49},[43,3117,3104],{"class":53},[43,3119,3120],{"class":49},"?.());\n",[92,3122,3124,3133,3158,3169],{"className":3123},[95],[97,3125,3127,3129,3130,3132],{"className":3126},[100],[102,3128],{"disabled":104,"type":105}," Both lines behave identically since ",[23,3131,3104],{}," is falsy either way",[97,3134,3136,117,3138,3141,3142,530,3145,3147,3148,3151,3152,3154,3155,3157],{"className":3135},[100],[102,3137],{"disabled":104,"type":105},[23,3139,3140],{},"user.getProfile()"," throws ",[23,3143,3144],{},"TypeError: user.getProfile is not a function",[23,3146,669],{}," is not callable, and plain (non-optional) call syntax always attempts the call; ",[23,3149,3150],{},"user.getProfile?.()"," correctly short-circuits to ",[23,3153,672],{}," instead, since ",[23,3156,3038],{}," checks for nullish before attempting to invoke",[97,3159,3161,117,3163,3165,3166,3168],{"className":3160},[100],[102,3162],{"disabled":104,"type":105},[23,3164,3150],{}," also throws, because ",[23,3167,805],{}," doesn't work on function calls, only property access",[97,3170,3172,3174,3175,3177],{"className":3171},[100],[102,3173],{"disabled":104,"type":105}," Neither line throws, since JS treats calling ",[23,3176,669],{}," as a no-op",[147,3179,3180,3182,3194],{},[150,3181,152],{},[154,3183,3184,3186,3187,3141,3189,879,3191,3193],{},[157,3185,159],{}," B — Plain calling ",[23,3188,669],{},[23,3190,516],{},[23,3192,3038],{}," correctly short-circuits instead",[154,3195,3196,117,3198,117,3200,3202,3203,3205,3206,3209,3210,773,3212,3214,3215,3217,3218,3220,3221,3224,3225,3227],{},[157,3197,171],{},[157,3199,960],{},[23,3201,3104],{}," here is ",[23,3204,669],{},", not a function — calling it directly attempts ",[23,3207,3208],{},"null()",", which is a ",[23,3211,516],{},[23,3213,669],{}," isn't callable. ",[23,3216,3038],{}," is specifically designed to guard exactly this: if the reference just before it is nullish, the call is skipped and the whole expression evaluates to ",[23,3219,672],{},". The idiomatic fix for code that might call a possibly-missing\u002Fpossibly-null method is exactly this optional call syntax rather than a manual ",[23,3222,3223],{},"typeof x === \"function\""," check everywhere. Option C is wrong — ",[23,3226,3038],{}," is valid, dedicated syntax for guarding function calls, not just property reads.",[14,3229,3230,3234,3288,3353],{"language":16},[18,3231,3233],{"id":3232},"q19-in-a-chain-of-mixed-logicalcomparison-operators-used-for-validation-whats-the-risk-of-relying-on-operator-precedence-instead-of-explicit-parentheses","Q19. In a chain of mixed logical\u002Fcomparison operators used for validation, what's the risk of relying on operator precedence instead of explicit parentheses?",[32,3235,3236],{"language":16},[35,3237,3239],{"className":37,"code":3238,"language":16,"meta":39,"style":39},"function canCheckout(cart, user) {\n  return cart.length > 0 && user.verified || user.isAdmin;\n}\n",[23,3240,3241,3260,3284],{"__ignoreMap":39},[43,3242,3243,3245,3248,3250,3253,3255,3258],{"class":45,"line":46},[43,3244,404],{"class":64},[43,3246,3247],{"class":53}," canCheckout",[43,3249,57],{"class":49},[43,3251,3252],{"class":412},"cart",[43,3254,660],{"class":49},[43,3256,3257],{"class":412},"user",[43,3259,416],{"class":49},[43,3261,3262,3264,3267,3270,3272,3274,3276,3279,3281],{"class":45,"line":75},[43,3263,437],{"class":64},[43,3265,3266],{"class":49}," cart.",[43,3268,3269],{"class":60},"length",[43,3271,1551],{"class":64},[43,3273,607],{"class":60},[43,3275,464],{"class":64},[43,3277,3278],{"class":49}," user.verified ",[43,3280,391],{"class":64},[43,3282,3283],{"class":49}," user.isAdmin;\n",[43,3285,3286],{"class":45,"line":434},[43,3287,446],{"class":49},[92,3289,3291,3302,3323,3336],{"className":3290},[95],[97,3292,3294,3296,3297,26,3299,3301],{"className":3293},[100],[102,3295],{"disabled":104,"type":105}," There's no risk; ",[23,3298,387],{},[23,3300,391],{}," always evaluate strictly left to right regardless of precedence",[97,3303,3305,117,3307,3309,3310,3312,3313,3316,3317,3319,3320,3322],{"className":3304},[100],[102,3306],{"disabled":104,"type":105},[23,3308,387],{}," binds tighter than ",[23,3311,391],{},", so this actually means ",[23,3314,3315],{},"(cart.length > 0 && user.verified) || user.isAdmin"," — which may be the intended logic, but relying on readers to recall that ",[23,3318,387],{}," outranks ",[23,3321,391],{}," (rather than writing the parens explicitly) risks misreadings and subtle bugs when the expression grows more complex",[97,3324,3326,117,3328,3309,3330,3332,3333],{"className":3325},[100],[102,3327],{"disabled":104,"type":105},[23,3329,391],{},[23,3331,387],{},", so this means ",[23,3334,3335],{},"cart.length > 0 && (user.verified || user.isAdmin)",[97,3337,3339,3341,3342,517,3344,26,3346,3348,3349,388,3351,1237],{"className":3338},[100],[102,3340],{"disabled":104,"type":105}," This is a ",[23,3343,312],{},[23,3345,387],{},[23,3347,391],{}," cannot be mixed without parentheses (like ",[23,3350,585],{},[23,3352,391],{},[147,3354,3355,3357,3368],{},[150,3356,152],{},[154,3358,3359,160,3361,3363,3364,3367],{},[157,3360,159],{},[23,3362,387],{}," binds tighter, meaning ",[23,3365,3366],{},"(... && ...) || ...","; explicit parens are still best practice to avoid misreadings",[154,3369,3370,117,3372,117,3374,3376,3377,3379,3380,388,3382,3384,3385,26,3387,3389,3390,388,3392,388,3394,3396,3397,388,3399,3401,3402,388,3404,3406],{},[157,3371,171],{},[157,3373,2418],{},[23,3375,387],{}," does have higher precedence than ",[23,3378,391],{}," (unlike the ",[23,3381,585],{},[23,3383,391],{}," combination, which the spec explicitly disallows without parens — see Q12 — ",[23,3386,387],{},[23,3388,391],{}," together are legal and well-defined). Here that means admins bypass the cart check entirely, which may or may not be the intended business logic. Because getting this precedence order wrong is an easy, silent mistake (and because ",[23,3391,387],{},[23,3393,391],{},[23,3395,585],{}," chains multiply in complexity fast), production code should make grouping explicit with parentheses even when not strictly required — self-documenting code beats a mentally-recalled precedence table. Option D wrongly extends the ",[23,3398,585],{},[23,3400,391],{}," restriction to ",[23,3403,387],{},[23,3405,391],{},", which don't share that restriction.",[14,3408,3409,3413,3483,3523],{"language":16},[18,3410,3412],{"id":3411},"q20-what-is-the-best-practice-way-to-compare-two-numbers-for-close-enough-equality-given-floating-point-imprecision","Q20. What is the best-practice way to compare two numbers for \"close enough\" equality given floating-point imprecision?",[32,3414,3415],{"language":16},[35,3416,3418],{"className":37,"code":3417,"language":16,"meta":39,"style":39},"function isCloseEnough(a, b) {\n  return a === b;\n}\nconsole.log(isCloseEnough(0.1 + 0.2, 0.3));\n",[23,3419,3420,3439,3451,3455],{"__ignoreMap":39},[43,3421,3422,3424,3427,3429,3432,3434,3437],{"class":45,"line":46},[43,3423,404],{"class":64},[43,3425,3426],{"class":53}," isCloseEnough",[43,3428,57],{"class":49},[43,3430,3431],{"class":412},"a",[43,3433,660],{"class":49},[43,3435,3436],{"class":412},"b",[43,3438,416],{"class":49},[43,3440,3441,3443,3446,3448],{"class":45,"line":75},[43,3442,437],{"class":64},[43,3444,3445],{"class":49}," a ",[43,3447,29],{"class":64},[43,3449,3450],{"class":49}," b;\n",[43,3452,3453],{"class":45,"line":434},[43,3454,446],{"class":49},[43,3456,3457,3459,3461,3463,3466,3468,3471,3473,3476,3478,3481],{"class":45,"line":443},[43,3458,50],{"class":49},[43,3460,54],{"class":53},[43,3462,57],{"class":49},[43,3464,3465],{"class":53},"isCloseEnough",[43,3467,57],{"class":49},[43,3469,3470],{"class":60},"0.1",[43,3472,1000],{"class":64},[43,3474,3475],{"class":60}," 0.2",[43,3477,660],{"class":49},[43,3479,3480],{"class":60},"0.3",[43,3482,2470],{"class":49},[92,3484,3486,3495,3505,3511],{"className":3485},[95],[97,3487,3489,3491,3492,3494],{"className":3488},[100],[102,3490],{"disabled":104,"type":105}," Keep using ",[23,3493,29],{},"; floating-point issues are rare enough to ignore in production",[97,3496,3498,3500,3501,3504],{"className":3497},[100],[102,3499],{"disabled":104,"type":105}," Compare the absolute difference against a small epsilon: ",[23,3502,3503],{},"Math.abs(a - b) \u003C Number.EPSILON"," (or a domain-appropriate tolerance), rather than exact equality, since binary floating-point arithmetic accumulates tiny representation errors",[97,3506,3508,3510],{"className":3507},[100],[102,3509],{"disabled":104,"type":105}," Convert both numbers to strings and compare those instead",[97,3512,3514,3516,3517,3519,3520,3522],{"className":3513},[100],[102,3515],{"disabled":104,"type":105}," Use ",[23,3518,25],{}," instead of ",[23,3521,29],{}," to allow \"reasonably close\" values to match",[147,3524,3525,3527,3532],{},[150,3526,152],{},[154,3528,3529,3531],{},[157,3530,159],{}," B — Compare via an epsilon-tolerant difference check instead of exact equality",[154,3533,3534,117,3536,3538,3539,3542,3543,3545,3546,3548,3549,3551,3552,3555,3556,2430,3559,3562,3563,3565,3566,3569,3570,3573,3574,973],{},[157,3535,171],{},[157,3537,2418],{}," as established in the Variables topic, ",[23,3540,3541],{},"0.1 + 0.2 !== 0.3"," due to IEEE-754 rounding, so ",[23,3544,3465],{}," above returns ",[23,3547,193],{}," for what a user would consider \"the same\" value. The standard fix is tolerance-based comparison — ",[23,3550,3503],{}," for values near the precision limit, or a larger domain-specific epsilon (e.g., ",[23,3553,3554],{},"0.0001",") for currency\u002Fmeasurement contexts. Option A dismisses a genuinely common bug source (any repeated decimal arithmetic — totals, percentages). Option C is a fragile workaround that breaks on formatting differences (",[23,3557,3558],{},"\"0.30000000000000004\"",[23,3560,3561],{},"\"0.3\"","). Option D is wrong — ",[23,3564,25],{}," performs ",[1468,3567,3568],{},"type"," coercion, not numeric fuzzy-matching; ",[23,3571,3572],{},"0.1 + 0.2 == 0.3"," is still ",[23,3575,193],{},[3577,3578,3579],"style",{},"html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":39,"searchDepth":75,"depth":75,"links":3581},[3582,3584,3586,3588,3590,3592,3593,3595,3597,3599,3600,3602,3604,3605,3607,3609,3611,3613,3614,3615],{"id":20,"depth":434,"text":3583},"Q1. What is the fundamental difference between == and ===?",{"id":204,"depth":434,"text":3585},"Q2. What does [] == ![] evaluate to?",{"id":383,"depth":434,"text":3587},"Q3. What is the difference between &&\u002F|| short-circuiting and how does it affect side effects?",{"id":581,"depth":434,"text":3589},"Q4. What does the nullish coalescing operator ?? do differently from ||?",{"id":801,"depth":434,"text":3591},"Q5. What does optional chaining ?. do when the left-hand side is null or undefined?",{"id":978,"depth":434,"text":979},{"id":1138,"depth":434,"text":3594},"Q7. What does associativity determine, and how does ** (exponentiation) differ from - (subtraction) in this regard?",{"id":1333,"depth":434,"text":3596},"Q8. What happens when you compare with \u003C\u002F> across mixed types, e.g., strings and numbers?",{"id":1510,"depth":434,"text":3598},"Q9. What is the result of comparing with NaN using relational operators?",{"id":1709,"depth":434,"text":1710},{"id":1848,"depth":434,"text":3601},"Q11. What does the unary + operator do to a string operand?",{"id":2098,"depth":434,"text":3603},"Q12. In a ?? b || c, what happens?",{"id":2241,"depth":434,"text":2242},{"id":2438,"depth":434,"text":3606},"Q14. What does typeof return for these edge-case expressions?",{"id":2651,"depth":434,"text":3608},"Q15. What is the idiomatic reason to prefer ===\u002F!== over ==\u002F!= in production code?",{"id":2795,"depth":434,"text":3610},"Q16. What is the best-practice way to write a conditional default value assignment when 0, \"\", or false might be legitimate values?",{"id":2941,"depth":434,"text":3612},"Q17. Which is the idiomatic pattern for guarding against null\u002Fundefined when calling a method that might not exist?",{"id":3069,"depth":434,"text":3070},{"id":3232,"depth":434,"text":3233},{"id":3411,"depth":434,"text":3412},"md",{},"\u002Fjs\u002F03-operators-and-expressions",{"title":5,"description":39},"js\u002F03-operators-and-expressions","sm70BNaZ5Y7lXZL5iyvU8IQN3nDjJp-Ctyinwd3-_uU",1787335397331]