🧠 JavaScript may be simple, but it hides a lot of interesting things under the hood. Even if you have been working with the language for years, knowledge of its internal mechanics, intricacies, and pitfalls will help you write cleaner, more predictable, and more efficient code. This article is a detailed guide to the key features of JavaScript, which will be useful not only for beginners, but also for experienced developers.

🚀 Topics we will cover:
Hoisting
Temporal Dead Zone
Function Declaration vs Function Expression
Shallow Copy vs Deep Copy
Object.assign
Slice vs Splice
forEach vs Map
Global Execution Context
Polyfilling
Deep dive into map()
Type Coercion
🪄 1. Hoisting
Hoisting is one of the most mysterious JavaScript mechanisms for beginners. This is the behavior of the engine, in which the declarations of variables and functions seem to "pop up" at the beginning of their scope.
This means that you can try to refer to a variable or function before it is actually declared — and sometimes it will even work:
console.log(a); // undefined
var a = 10;var — pops up and initializes undefined, while let and const pop up but do not initialize. Therefore, the following code will cause an error:
console.log(b); // ReferenceError
let b = 20;As for the functions, here is the difference between function declaration and function expression is especially important:
console.log(getNum()); // OK
function getNum() { return 42; }
console.log(getArrow()); // TypeError: getArrow is not a function
var getArrow = () => 42;📸 Prompt for photo: "Infographic about hoisting in JavaScript, with separation of variables var/let/const and function/function expression"
🕳 2. Temporal Dead Zone (TDZ)
A temporary dead zone is a period in which a variable has already been declared (via let or const), but has not yet been initialized. In TDZ, any attempt to access a variable causes ReferenceError.
console.log(value); // ReferenceError
let value = 100;This mechanism protects us from errors and makes the behavior of the code more predictable. TDZ also applies to functions defined as const and let.
🧩 3. Function Declaration vs Function Expression
Function Declaration
function greet() {
console.log("Hello!");
}Such functions pop up and can be called anywhere in the scope. This is convenient if the logic of the function should be available throughout the script.
Function Expression
const greet = function() {
console.log("Hello!");
}Here, the function becomes available only after the variable is assigned. This is great for use in closures or callbacks.
📦 4. Shallow Copy vs Deep Copy
Shallow Copy
It copies only the top level of the object's properties. Nested objects continue to refer to the same memory areas:
const obj1 = { name: "Olga", address: { city: "Kazan" } };
const obj2 = { ...obj1 };
obj2.address.city = "Ufa";
console.log(obj1.address.city); // "Ufa"Deep Copy
Allows you to completely copy an object, including nested structures:
const deepCopy = structuredClone(obj1);
deepCopy.address.city = "Sochi";Alternatives:
JSON.stringify/parse— does not work with functions andundefinedstructuredClone— a modern methodUser-defined recursive function
📸 Prompt for photo: "Comparison of shallow and deep copying with visualization of nested objects"
🔄 5. Object.assign()
The method allows you to copy properties from one or more objects to the target:
const objA = { name: "Alice" };
const objB = { age: 30 };
const result = Object.assign({}, objA, objB);Features:
Returns the target object
Copies only its own enumerated properties
Overwrites properties of the same name
Alternative — spread syntax: { ...objA, ...objB }
✂️ 6. Slice vs Splice
slice() and splice() are array methods that are often confused with each other:
slice(start, end)— returns a new array without changing the originalsplice(start, deleteCount, ...items)— modifies the array in place
const arr = [1, 2, 3, 4, 5];
console.log(arr.slice(1, 3)); // [2, 3]
console.log(arr.splice(1, 2, 9, 9)); // [2, 3], arr now [1, 9, 9, 4, 5]🔁 7. forEach vs map
Both methods iterate through the array, but there are nuances:
Feature | forEach | map |
|---|---|---|
Returns a new array | ❌ | ✅ |
Can you exit the loop? | ❌ | ❌ |
Used for | Side effects | Transformations |
[1, 2, , 4].map(x => x || 0); // processing sparse arrayIf you need to stop the execution, use for, for...of, some or every.
🌍 8. Global Execution Context
Execution context — this is the environment in which the code is executed. There are two types:
Global — created first, contains global variables, functions, and the
thisobject.Functional — is created when each function is called.
After the script is completed, the global context is deleted.
🛠 9. Polyfilling
Polyfills allow you to emulate the behavior of new language features in older browsers.
Example: polyfill for Array.prototype.includes:
if (!Array.prototype.includes) {
Array.prototype.includes = function(el) {
return this.indexOf(el) !== -1;
};
}Polyfills are especially important when developing cross-browser solutions.
🗺 10. Map Deep Dive
The map() method takes three arguments:
value
index
source array
const data = [1, 2, , 4];
const result = data.map((val, idx, arr) => val ? val * 2 : (arr[idx - 1] || 1));Features:
Skipped items (
empty slots) are ignoredNew elements added during execution are not processed
Removed before execution - skipped
⚖️ 11. Type Coercion
Implicit:
10 + "2"; // "102"
10 - "2"; // 8
true + 1; // 2
[] + 1; // "1"
null + 1; // 1
undefined + 1; // NaNExplicit:
String(123);
Number("456");
Boolean(0); // falseIt is important to understand how and when the conversion occurs to avoid unexpected bugs.
📝 Conclusion
📚 A deep understanding of the inner workings of JavaScript will help you not just write code, but design application architecture more reliably and clearly. This is especially important in team development, where readability and predictability of behavior are critical.
Having analyzed such topics as hoisting, TDZ, types of functions, copying objects, features of map and forEach, as well as typecasting, you reach the level where JavaScript ceases to be just a language — it becomes a tool for fine-tuning logic.
