Topic 004: Concept refresher
let a = 3;
console.log(a);
let a = 5;
console.log(a);In JavaScript, you cannot declare the same variable twice using let within the same scope. If you try to do so, it will result in a syntax error. So, the code you provided will throw an error at the second let a = 5 declaration.
To fix this, you can either change the second let a = 5 to just a = 5, or if you want to redeclare a, you would use var or const for the first declaration and let for the second. Here's the corrected version:
let a = 3;
console.log(a);
a = 5; // Reassigning the value of 'a'
console.log(a);This will output:
3
5
-
console.log(3 + "3"): This will output"33". When you use the+operator with a number and a string, JavaScript coerces the number into a string and performs string concatenation. -
console.log(3 - "3"): This will output0. JavaScript tries to perform arithmetic operations, so it will try to convert the string"3"into a number and subtract it from3, resulting in0. -
console.log(+"3" + 3): This will output6. The unary plus operator (+) converts the string"3"into a number, and then adds3to it, resulting in6. -
console.log("3" == 3): This will outputtrue. The loose equality operator (==) performs type coercion, so it converts the string"3"into a number before comparing, which results intruebecause3is equal to3. -
console.log("3" === 3): This will outputfalse. The strict equality operator (===) does not perform type coercion, so it compares the string"3"with the number3directly, resulting infalsebecause they are of different types. -
console.log(1 < 2 < 3): This will outputtrue. This expression is evaluated left-to-right.1 < 2evaluates totrue, which is converted to1in numerical comparison, so1 < 3also evaluates totrue. -
console.log(3 > 2 > 1): This will outputfalse. This expression is also evaluated left-to-right.3 > 2evaluates totrue, which is converted to1in numerical comparison. Then1 > 1evaluates tofalse. -
console.log(isNaN('12')): This will outputfalse. TheisNaN()function checks if a value is "Not-a-Number". However, the string'12'can be coerced into a number, so it's not NaN, resulting infalse.
In the provided JavaScript code:
function print() {
var x = 21;
let y = 20;
console.log(window.x);
console.log(window.y);
}
print();-
Inside the function
print(), two variables are declared:xusingvarandyusinglet. -
Variable
xis declared usingvar, which means it becomes a property of the global object (windowobject in browsers) because it's declared outside any function or block scope. So,window.xwill refer to the variablexdeclared usingvar. -
Variable
yis declared usinglet, which means it's block-scoped to theprint()function and not attached to the global object. Therefore,window.ywill beundefined. -
The function is called
print(). -
Inside the function,
console.log(window.x)will log the value ofxattached to the global object (windowin a browser), which is21. -
console.log(window.y)will logundefinedbecauseyis not attached to the global object due to being declared withlet. -
Therefore, the output of the function will be:
21 undefined
-
In JavaScript, scope refers to the accessibility of variables. There are three types of scopes: block scope, local scope, and global scope. Let me explain each with code examples:
-
- . Block Scope: Introduced in ES6 with the
letandconstkeywords, block scope confines variables within the nearest curly braces{}. Variables declared withletorconstinside a block are only accessible within that block.
- . Block Scope: Introduced in ES6 with the
{
let x = 10; // block-scoped variable
console.log(x); // Output: 10
}
console.log(x); // Error: x is not defined-
- Local Scope: Variables declared within a function have local scope. They are accessible only within that function.
function myFunction() {
var y = 20; // local variable
console.log(y); // Output: 20
}
myFunction();
console.log(y); // Error: y is not defined-
- Global Scope: Variables declared outside of any function or block have global scope. They can be accessed from anywhere in the code.
var z = 30; // global variable
function anotherFunction() {
console.log(z); // Output: 30
}
console.log(z); // Output: 30var globalVariable = 10; // Global variable
function print() {
var localVariable = 21; // Local variable to the function
{
let blockVariable = 22; // Block-scoped variable
console.log("Inside block:", blockVariable); // Accessible inside the block
}
console.log("Inside function - localVariable:", localVariable); // Accessible inside the function
console.log("Inside function - globalVariable:", globalVariable); // Accessible inside the function
console.log("Inside function - window.globalVariable:", window.globalVariable); // Accessible inside the function via window object
}
print();
console.log("Outside function - globalVariable:", globalVariable); // Accessible globallyRemember, accessing variables in broader scopes (e.g., global from within a function) is allowed, but accessing variables in narrower scopes (e.g., local from outside its function) will result in an error.
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1000);
}- The
forloop initializes a block-scoped variableiwith a value of0. - It checks the condition
i < 5. - If the condition is
true, it executes the loop body and incrementsiby1. - Inside the loop body:
setTimeout()is used to schedule the execution of a function after a specified delay (in milliseconds).- An arrow function is passed to
setTimeout(), which logs the value ofito the console. - However, this logging function is not executed immediately; it is scheduled to be executed after a delay of
1000milliseconds (1 second).
- This process repeats until the condition
i < 5becomesfalse(i.e., afterireaches5). - Since
iis declared usinglet, it's block-scoped, meaning a new lexical environment is created for each iteration of the loop. This ensures that each invocation of the arrow function insidesetTimeout()captures the value ofiat the time of its execution. - As a result, after 1 second, the logged values will be
0,1,2,3, and4, respectively, as expected. This is because each scheduled execution of the arrow function insidesetTimeout()captures the value ofiat the time of its iteration.
In the provided JavaScript code:
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1000);
}- The
forloop initializes a variableiwith a value of0. - It checks the condition
i < 5. - If the condition is
true, it executes the loop body and incrementsiby1. - Inside the loop body:
setTimeout()is used to schedule the execution of a function after a specified delay (in milliseconds).- An arrow function is passed to
setTimeout(), which logs the value ofito the console. - However, this logging function is not executed immediately; it is scheduled to be executed after a delay of
1000milliseconds (1 second).
- This process repeats until the condition
i < 5becomesfalse(i.e., afterireaches5). - When the loop finishes executing, the value of
iwill be5.
Now, let's discuss the behavior of setTimeout() inside the loop:
- Even though
setTimeout()is called multiple times within the loop, the functions passed tosetTimeout()are not executed immediately. Instead, they are executed asynchronously after the specified delay. - Because of the asynchronous nature of
setTimeout(), by the time the functions passed to it are executed (after a delay of 1 second), the loop has already completed, and the value ofihas become5. - Since the logging function captures the reference to
iby closure, it will print the value ofiat the time of execution, which is5for all the scheduled executions.
So, when this code runs, after a delay of 1 second, it will log 5 to the console five times. This is because by the time the logging functions are executed, the loop has already finished executing and the value of i is 5.
Using a closure inside the loop to capture the value of i at each iteration. Here's how you can print 0, 1, 2, 3, and 4 instead of five times 5 using var:
for (var i = 1; i < 5; i++) {
(function (index) {
setTimeout(function () {
console.log(index);
}, 1000 * index);
})(i);
}In this code:
- We use a
forloop to iterate from1to5. - Inside the loop, we immediately invoke a function expression (an IIFE - Immediately Invoked Function Expression) which takes
ias an argument and captures its value in the parameterindex. - We then pass
indextosetTimeout()to schedule the logging ofindexafter a delay. Since eachsetTimeout()call captures the value ofindexat the time it's invoked, it prints1after 1 second,2after 2 seconds, and so on, until5after 5 seconds.
This way, we print 1 2 3 4 5 to the console using only var.
In the below JavaScript code:
x = 10;
console.log(x);
var x;- The variable
xis assigned the value10without being declared usingvar,let, orconst. In JavaScript, this is allowed due to the concept of variable hoisting. Hoisting means that variable declarations are moved to the top of their containing scope during the compilation phase, although their assignments remain in place. - When the code is executed,
xis assigned the value10. - Then,
console.log(x)logs the value ofx, which is10. - After that,
var x;is encountered. Despite being declared later in the code, the declaration ofxwithvaris hoisted to the top of its scope. However, sincexhas already been assigned a value (10), this declaration doesn't affect the value ofx. - Therefore, the output of the code will be:
10
In the below JavaScript code:
x = 10;
y = 10;
console.log(x);
console.log(y);
const y;
let x;-
x = 10;: This assigns the value10to the variablex. Sincexis not declared usingvar,let, orconst, it becomes a global variable. -
y = 10;: This assigns the value10to the variabley. Similar tox, sinceyis not declared usingvar,let, orconst, it also becomes a global variable. -
console.log(x);: This prints the value ofxto the console. The value ofxis10. -
console.log(y);: This prints the value ofyto the console. The value ofyis also10. -
const y;: This line attempts to declare the variableyusingconst. However, sinceyhas already been assigned a value (10) before its declaration, this will result in a syntax error. In JavaScript,constrequires an initialization at the point of declaration and cannot be assigned a value later. -
let x;: This line declares the variablexusinglet. However, sincexhas already been assigned a value (10) before its declaration, this will not result in an error. But declaringxhere will not have any effect on the previously assigned value ofx.
Therefore, the code will throw a syntax error at the line const y; due to the attempt to declare a const variable without initialization, and it will output 10 for both x and y before encountering the error.
1. Concise Syntax: Arrow functions have a compact and concise syntax, making the code more readable and reducing the amount of boilerplate code. They are particularly useful for writing shorter and more expressive functions.
2. Lexical this Binding: Arrow functions do not have their own this value. Instead, they lexically bind the this value of the enclosing scope. This means that the this value inside an arrow function is automatically inherited from the surrounding context. It eliminates the need to use bind(), call(), or apply() to preserve the this value or deal with this-related issues.
3. No Arguments Object: Arrow functions do not have their own arguments object. Instead, they inherit the arguments object from the enclosing scope. This can be beneficial in scenarios where you need to access the arguments passed to an enclosing function.
4. Implicit Return: Arrow functions provide implicit return behavior for concise one-line functions. If the function body consists of a single expression, you can omit the curly braces and the return keyword. The result of the expression will be automatically returned.
5. Well-suited for Callbacks: Arrow functions are well-suited for callback functions, such as event handlers or asynchronous operations, where the lexical binding of this and the concise syntax can make the code more readable and maintainable.