๐ง Complex & "Weird" JavaScript Features You Should Know
JavaScript is a powerful, dynamic, and highly flexible language โ and with that flexibility comes some truly strange behaviors. Here, we dive into the most advanced and weird features of JavaScript that often trip up even seasoned developers.
๐ 1. Coercion Madness (Type Conversion)
[] + [] // ""
[] + {} // "[object Object]"
{} + [] // 0 (or "[object Object]" depending on context)
true + false // 1
null + 1 // 1
undefined + 1 // NaNโ ๏ธ
+is both addition and string concatenation operator depending on operand types. Empty arrays coerce to empty strings. Objects to[object Object].
๐ 2. Function Hoisting Oddities
hoisted(); // "Hoisted!"
function hoisted() {
console.log("Hoisted!");
}
notHoisted(); // โ TypeError
var notHoisted = function () {
console.log("Not hoisted");
};Functions declared with function are fully hoisted. var declarations are hoisted but not their assignments.
๐ฆ 3. Closures Inside Loops
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // Logs: 3, 3, 3
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // Logs: 0, 1, 2let creates block-scoped variables, preserving loop state. var is function-scoped.
๐ 4. Object Keys Are Always Strings (Or Symbols)
const a = {};
a[1] = "one";
a[true] = "bool";
a[{}] = "object";
console.log(a); // All keys coerced to strings!Objects coerce keys to strings unless you use
Mapwhich preserves key types.
๐ง 5. this Keyword Quirks
const obj = {
name: "JS",
say: function () {
console.log(this.name);
},
};
const say = obj.say;
say(); // undefined (in strict mode), or global object in non-strict
obj.say(); // "JS"
thisis dynamic. Arrow functions lexically bindthis, while regular functions do not.
๐ 6. Double Equals (==) Weirdness
0 == '0' // true
false == 'false' // false
false == '0' // true
null == undefined // true
[] == false // true
[] == ![] // trueUse === for safety unless you really know what you're doing.
๐ฅ 7. The Temporal Dead Zone (TDZ)
console.log(a); // โ ReferenceError
let a = 10;Variables declared with
letandconstare hoisted, but not initialized โ they live in the TDZ until the line of declaration.
๐งช 8. typeof null
typeof null; // "object" (Legacy bug)A long-standing bug that remains for backward compatibility.
๐งฌ 9. NaN Is Not Equal to Itself
NaN === NaN; // false
Number.isNaN(NaN); // trueUse Number.isNaN instead of ===.
๐ญ 10. with Statement & Strict Mode
with (Math) {
console.log(PI);
} // Bad practice
withis disallowed in strict mode and considered bad practice. It makes scope resolution unpredictable.
๐งฉ 11. Symbol and Hidden Properties
const obj = {};
const key = Symbol("hidden");
obj[key] = 123;
console.log(Object.keys(obj)); // []Symbols allow for non-enumerable, "hidden" properties.
๐งต 12. Generators and Async Iteration
function* gen() {
yield 1;
yield 2;
}
for (let val of gen()) {
console.log(val);
}Generators pause and resume execution โ useful for stateful logic or lazy evaluation.
๐งจ 13. Proxies
const handler = {
get: (target, prop) => (prop in target ? target[prop] : "๐คทโโ๏ธ"),
};
const obj = new Proxy({}, handler);
console.log(obj.name); // "๐คทโโ๏ธ"Proxies allow for meta-programming. Can intercept and customize behavior for objects.
๐ง 14. Tagged Template Literals
function tag(strings, ...values) {
return strings.reduce((acc, s, i) => acc + s + (values[i] || ""), "");
}
const result = tag`Hello, ${"JS"}!`;
console.log(result); // "Hello, JS!"Tags let you modify how template strings are parsed.
๐งช 15. Object Destructuring with Renaming & Defaults
const { a: alpha = 10, b: beta = 20 } = { a: 5 };
console.log(alpha, beta); // 5, 20