Var vs Let and Const
Consider the following code:
function sayHi() {
console.log(name);
console.log(age);
var name = "Alex";
let age = 24; }
If you run this function, the output will be:
Consider the following code:
function sayHi() {
console.log(name);
console.log(age);
var name = "Alex";
let age = 24; }
If you run this function, the output will be:
undefined
ReferenceError
Why does this happen?
Variables declared with var are hoisted to the top of their scope during the compilation phase.
Hoisting means JavaScript creates a memory space for the variable before the code executes, but it does not assign a value yet. Instead, the variable is initialized with undefined.
That’s why when we log name before its assignment, we see undefined instead of an error.
Variables declared with let and const are also hoisted, but the key difference is that they are not initialized automatically.
They remain in a special state called the Temporal Dead Zone (TDZ) from the start of their scope until the line where they are actually assigned a value.
If you try to access them in this zone (before initialization), JavaScript throws a ReferenceError.
In short:
var → hoisted and initialized with undefined immediately.
let & const → hoisted but stay uninitialized (TDZ) until the code execution reaches their declaration.
Arrow Functions vs Regular Functions in JavaScript
Let’s look at this code example:
const square = {
sideOfSquare: 10,
// Regular function area() {
return this.sideOfSquare * this.sideOfSquare;
},
// Arrow function
perimeter: () => this.sideOfSquare * 4 };
console.log(square.area()); // 100
console.log(square.perimeter()); // NaN
Why does this happen?
Regular function (area)
When you use a regular function inside an object, this refers to the object itself (square).
That means this.sideOfSquare correctly points to 10, so the result of area() is 100.
Arrow function (perimeter)
Arrow functions don’t have their own this.
Instead, they use the this value from the outer scope (the place where the function was created).
In this case, the arrow function is created inside the object literal, but the this it captures is not the object itself — it’s usually the global scope (window in browsers or undefined in strict mode).
Since there’s no sideOfSquare in the global scope, the result is NaN.
In Short:
Use regular functions when you need this to refer to the object.
Use arrow functions when you want to preserve the this from the outer scope (for example, inside callbacks).
Dot notation vs Bracket notation
Consider this code:
const bird = { size: "small" }
const mouse = {
name: "Mickey",
small: true
};
We can perform something like this:
mouse[bird.size] → because bird.size gives us "small", which will be evaluated as mouse["small"] = true. So this is valid.
Another option is:
mouse[bird["size"]] → because the inner operation also gives "small", leading to mouse["small"].
What is wrong is trying:
mouse.bird.size → here mouse.bird is undefined, so accessing .size will throw an error (undefined.size).
In short:
Dot notation: The key must literally exist as a property.
Bracket notation: The key can be a variable or expression that resolves to a property name.
Top comments (0)