17 KiB
Agenda
- JS refresher
- TypeOf Operator
- Objects and JSON
- JS Code Execution - Hoisting and Execution Context
- Hoisting
- Execution Context
- let, var, and const:
- Shadowing: legal and illegal
JavaScript is a dynamically typed, high-level programming language commonly used in web development. It employs the V8 engine, written in C++, for high-performance execution. Despite its name, JavaScript is distinct from Java. Its dynamic nature allows variables to change types during runtime, offering flexibility in coding.
Datatypes in JS
Certainly, here's the information about JavaScript data types:
Primitive Data Types:
- Number
- String
- Null
- Undefined
- Boolean
New Primitive Types:
- BigInt
- Symbol
Non-Primitive Types (Reference Types):
- Object
- Functions
- Arrays
New Non-Primitive Types:
- Map
- Set
- WeakMap
- WeakSet
Sure, here are the code snippets with explanations and their respective outputs:
-
Numbers:
console.log(5 / 2); // Output: 2.5
Explanation: JavaScript performs the division operation, and the result is
2.5
, which is a floating-point number. -
Strings:
let age = 25; let str1 = 'I am ' + age + " years old "; console.log(str1); // Output: I am 25 years old let templateString = `I am ${age} years old`; console.log(templateString); // Output: I am 25 years old
Explanation: In the first part, string concatenation is used to create
str1
. In the second part, a template string with variable interpolation is used to createtemplateString
, both resulting in the same output. -
Null and Undefined:
let myNull = null; let myUndefined; console.log(myNull); // Output: null console.log(myUndefined); // Output: undefined
Explanation:
myNull
is explicitly set tonull
, whilemyUndefined
is declared but not assigned a value, resulting inundefined
. -
typeof Operator:
var a = 10; console.log(typeof a); // Output: number a = "string"; console.log(typeof a); // Output: string a = { "name": "Jasbir" }; console.log(typeof a); // Output: object
Explanation: The
typeof
operator is used to determine the data type of the variablea
. It returns"number"
,"string"
, and"object"
based on the assigned value. -
typeof null and Array Check:
console.log(typeof null); // Output: object let arr = [1, 2, 3, 4]; console.log(Array.isArray(arr)); // Output: true
Explanation:
typeof null
returns"object"
(historical quirk), andArray.isArray()
accurately checks whetherarr
is an array and returnstrue
.
These code snippets demonstrate JavaScript's handling of data types and the use of the typeof
operator and Array.isArray()
to determine types and check arrays.
Non Primitive
function
Certainly, here's the code snippet related to functions and a brief explanation:
// Function Definition
function fn(param1) {
console.log("Hello world!", param1);
return "Returned value";
}
// Function Call
let rVal = fn();
console.log("Return value:", rVal);
Explanation:
-
function fn(param1)
: This is a function definition namedfn
that takes one parameterparam1
. Inside the function, it logs "Hello world!" along with the value ofparam1
and then returns the string "Returned value." -
let rVal = fn();
: This line calls thefn
function without passing any arguments. Since the function expects a parameter,param1
inside the function will beundefined
. It also captures the return value of the function in the variablerVal
. -
console.log("Return value:", rVal);
: Finally, it logs the string "Return value:" along with the value ofrVal
, which is "Returned value."
Please note that calling fn
without passing a value for param1
will not result in an error, but param1
will be undefined
inside the function. If you want to pass a value when calling the function, you should do so like this: fn("SomeValue");
.
Objects and JSON
Here's the code snippet related to JavaScript objects and a brief explanation:
// Object Definition
let cap = {
name: "Steve",
age: 34,
isAvenger: true,
key: "hello"
}
// Loop through Object Properties
for (let key in cap) {
console.log(key, " ", cap[key], " ", cap.key);
}
Explanation:
-
An object in JavaScript is a collection of key-value pairs where the key can be a number or a string, and the value can be any valid JavaScript data type.
-
cap
is an object that represents an entity, possibly a character named "Steve." It contains properties likename
,age
,isAvenger
, andkey
. -
The
for...in
loop is used to iterate through the properties of thecap
object. Inside the loop,key
represents each property name, andcap[key]
retrieves the value associated with that property. -
The
console.log
statement within the loop logs thekey
, the corresponding value accessed usingcap[key]
, andcap.key
. However, note thatcap.key
accesses the property named "key" specifically, whereascap[key]
dynamically accesses the property corresponding to the currentkey
in the loop. -
In JavaScript, you can access object properties using the dot notation (e.g.,
cap.name
) or square brackets (e.g.,cap['last Name']
). -
JSON (JavaScript Object Notation) is a widely used data interchange format that is based on the structure of JavaScript objects. JSON uses a similar syntax for key-value pairs but is typically used for data communication between systems.
This code snippet demonstrates the creation of a JavaScript object, accessing its properties using a loop and dot notation, and the dynamic nature of accessing properties using square brackets.
JS Code Execution
Call Stack:
The call stack is a data structure used in JavaScript to keep track of the currently executing function(s). It follows the Last-In-First-Out (LIFO) principle, which means that the most recently called function is the first one to complete. As functions are called, they are added to the stack, and as they complete, they are removed from the stack.
Execution Context:
An execution context is a conceptual container that holds all the information related to the execution of a piece of code. Each function call creates a new execution context, which includes information like the function's variables, parameters, references to outer scopes, the value of this
, and other internal details.
Global Area:
The global area, also known as the global scope, is where global variables and functions are defined. It's the outermost scope in JavaScript. Code outside of any function is executed in the global scope. The global area has its own execution context.
Breakdown of Code Execution:
Certainly, here's the code snippet you provided along with an explanation of the code's execution and expected output:
let a = 10;
function fn() {
console.log("I am fn");
function inner() {
console.log("I am inner");
}
inner();
}
fn();
Explanation:
-
let a = 10;
: This declares a variablea
and assigns it the value10
. -
function fn() { ... }
: This defines a function namedfn
. Insidefn
, there's another function definition namedinner
. -
console.log("I am fn");
: When thefn
function is called, it logs "I am fn" to the console. -
function inner() { ... }
: This defines an inner function namedinner
within thefn
function. -
inner();
: Inside thefn
function,inner()
is called. This means the "I am inner" message will be logged to the console. -
fn();
: Finally, thefn
function is called, which in turn callsinner()
. So, both "I am fn" and "I am inner" messages will be logged to the console.
Expected Output:
I am fn
I am inner
This code demonstrates the concept of nested functions. The fn
function contains an inner function inner
, and when fn
is called, it executes both its own code and the code within inner
, resulting in both log messages being displayed in the console.
JS Code Execution Quiz
Consider the following JavaScript code:
function real() {
console.log("I am real. Always run me");
}
function real() {
console.log("No I am real one ");
}
real();
function real() {
console.log("You both are wasted");
}
What will be the output when the code is executed?
- "No I am real one"
- "You both are wasted"
- Error
Explanation
In JavaScript, when you declare multiple functions with the same name, only the last one defined will be retained due to hoisting. Therefore, in this code:
- The first two function declarations are overwritten by the last one.
- The real() function is called, and the last version of the function's body is executed, which logs "You both are wasted" to the console. Hence, the correct answer is B) "You both are wasted".
Execution of the code in JS
It seems like you're describing the code execution process in JavaScript and how execution contexts (EC) work. Here's a breakdown of your explanation:
-
Code Execution Process:
- Code in JavaScript is executed within execution contexts (ECs).
-
Global Code Execution (GEC):
- The global code is executed in the Global Execution Context (GEC). It's the top-level context where the entire script starts.
-
Inside a Function (Function Execution Context):
- When a function is called, its code is executed within its own Function Execution Context.
-
Execution Context Creation (EC Creation):
- During EC creation, JavaScript performs hoisting, which involves memory allocation for variables (initialized with
undefined
) and function declarations (fully allocated). - It also sets up the outer scope (if any) and determines the value of the
this
keyword.
- During EC creation, JavaScript performs hoisting, which involves memory allocation for variables (initialized with
-
Global Object (Browser/Node.js):
- In a browser environment, the global object is
window
. In Node.js, it'sglobal
. These objects contain global variables and functions.
- In a browser environment, the global object is
-
Outer Scope:
- Each execution context has access to variables and functions in its outer (enclosing) scope.
-
this
Keyword:- The
this
keyword is determined based on the context in which a function is executed. Its value varies depending on how the function is called.
- The
-
Execution of Code:
- After EC creation, the code within the context is executed. Variables and functions are accessible, and the program flows according to the code logic.
This explanation outlines the sequence of events when JavaScript code is executed, starting with EC creation, hoisting, and variable/function allocation, and then proceeding with the actual code execution. Understanding execution contexts is essential to grasp how JavaScript manages variable scope and function execution.
Code Snippet 1:
var a=10;
real();
function real() { console.log("I am real. Always run me"); }
Explanation:
-
var a=10;
: Declares a variablea
and assigns it the value10
. -
real();
: Calls the functionreal()
. -
function real() { console.log("I am real. Always run me"); }
: Defines a functionreal()
that logs a message to the console.
Expected Output:
I am real. Always run me
In this case, the function real()
is defined before it is called, so it executes without any issues.
Code Snippet 2:
let a = 10;
function fn() {
console.log("a", a);
}
fn();
Explanation:
-
let a = 10;
: Declares a variablea
usinglet
and assigns it the value10
. This variable is in the outer/global scope. -
function fn() { console.log("a", a); }
: Defines a functionfn()
that logs the value ofa
to the console. It captures the value ofa
from its outer scope. -
fn();
: Calls the functionfn()
.
Expected Output:
a 10
In this case, fn()
accesses the variable a
from its outer scope (the global scope) and logs its value, which is 10
.
Let, Var and Const
Certainly, let's break down the provided code snippet step by step and explain the output:
let a = 10;
console.log("line number 2", a);
function fn() {
let a = 20;
console.log("line number 4", a);
a++;
console.log("line number 7", a);
if (a) {
let a = 30;
a++;
console.log("line number 11", a);
}
console.log("line number 13", a);
}
fn();
console.log("line number 16", a);
Explanation:
-
let a = 10;
: Declares a variablea
in the outer/global scope and assigns it the value10
. -
console.log("line number 2", a);
: Logs the value ofa
in the global scope, which is10
. -
function fn() { ... }
: Defines a function namedfn()
. -
Inside the
fn
function:let a = 20;
: Declares a new variablea
in the function scope (local to the function) and assigns it the value20
.console.log("line number 4", a);
: Logs the value of the locala
, which is20
.a++;
: Increments the locala
to21
.console.log("line number 7", a);
: Logs the updated locala
, which is21
.
-
Inside the
if
block:let a = 30;
: Declares a new variablea
with block scope (inside theif
block) and assigns it the value30
.a++;
: Increments the block-scopeda
to31
.console.log("line number 11", a);
: Logs the block-scopeda
, which is31
.
-
After the
if
block, but still within the function:console.log("line number 13", a);
: Logs the function-scopeda
, which is21
.
-
fn();
: Calls thefn()
function. -
console.log("line number 16", a);
: Logs the globala
value, which is10
.
Expected Output:
line number 2 10
line number 4 20
line number 7 21
line number 11 31
line number 13 21
line number 16 10
This code demonstrates variable scoping in JavaScript, including global, function, and block scope. Variables with the same name declared in different scopes do not interfere with each other. Block-scoped let
variables are confined to the block in which they are declared, and the variable declared inside the if
block doesn't affect the function-scoped or global a
.
Shadowing
Variable Shadowing occurs when a variable declared within a certain scope has the same name as a variable declared in an outer scope. This can lead to confusion and unexpected behavior, especially when accessing or modifying the variables. Let's explore legal and illegal cases of variable shadowing in more detail.
Let's go through the provided code snippets step by step and explain the output for each one:
Code Snippet 1:
let fruits = "apple";
console.log(fruits); // apple
{
console.log(fruits); // ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
let fruits;
console.log(fruits); // undefined
fruits = "orange";
{
console.log(fruits); // orange
}
console.log(fruits); // orange
}
console.log(fruits); // apple
Explanation:
-
A variable
fruits
is declared and initialized with the value"apple"
in the global scope. -
Inside a block, a
console.log(fruits)
statement attempts to log the value offruits
before it's declared within that block. This results in aReferenceError
because of the Temporal Dead Zone (TDZ) forlet
variables. -
A new
let
variable namedfruits
is declared within the block. It's initially in the TDZ, soconsole.log(fruits)
logsundefined
. -
fruits
is assigned the value"orange"
. -
Inside a nested block,
console.log(fruits)
logs"orange"
because it refers to the block-scopedfruits
. -
Outside the innermost block,
console.log(fruits)
still logs"orange"
because it refers to the most recent block-scopedfruits
. -
Finally, outside the block,
console.log(fruits)
logs the globalfruits
value, which is"apple"
.
Expected Output:
apple
ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
undefined
orange
orange
apple
Code Snippet 2:
var fruits = "apple";
console.log("21", fruits); // apple
{
let fruits;
fruits = "orange";
console.log("25", fruits); // orange
{
let fruits;
console.log("28", fruits); // undefined
}
console.log(fruits); // orange
}
console.log(fruits); // apple
Explanation:
-
A variable
fruits
is declared and initialized with the value"apple"
usingvar
in the global scope. -
Inside a block, a new
let
variable namedfruits
is declared, shadowing the globalfruits
. It is assigned the value"orange"
within this block. -
Inside a nested block, another
let
variable namedfruits
is declared. This variable shadows the outer block-scopedfruits
. It is not initialized within this block, so it logsundefined
. -
Outside the innermost block,
console.log(fruits)
logs the block-scopedfruits
, which is"orange"
. -
Finally, outside the block,
console.log(fruits)
logs the globalfruits
, which is"apple"
.
Expected Output:
21 apple
25 orange
28 undefined
orange
apple
In this code, variable shadowing occurs when a variable with the same name is declared inside a nested block, shadowing variables from outer scopes. The behavior differs between var
and let
declarations, as demonstrated in the code snippets.