[Go to site: main page, start]

0% found this document useful (0 votes)
7 views91 pages

JavaScript Concepts and Comparisons Guide

The document provides an extensive overview of JavaScript, comparing it with Java and TypeScript, detailing their differences in typing, concurrency, and inheritance. It also covers advanced JavaScript topics, Babel configuration for transpiling modern JavaScript code, and the use of tools like Webpack. Overall, it serves as a comprehensive guide for understanding JavaScript and its ecosystem, including best practices for development.

Uploaded by

Yifan Zou
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views91 pages

JavaScript Concepts and Comparisons Guide

The document provides an extensive overview of JavaScript, comparing it with Java and TypeScript, detailing their differences in typing, concurrency, and inheritance. It also covers advanced JavaScript topics, Babel configuration for transpiling modern JavaScript code, and the use of tools like Webpack. Overall, it serves as a comprehensive guide for understanding JavaScript and its ecosystem, including best practices for development.

Uploaded by

Yifan Zou
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

JavaScript

JavaScript vs Java
JavaScript vs Typescript
Babel
Webpack
Prototype
ES5 vs ES6
JavaScript Variables: Global and local variables
JavaScript Variables: Variable shadowing
JavaScript Variables: Non-strict mode
JavaScript Variables: strict mode
JavaScript Variables: hoisting
JavaScript Variables: var, let, const
Primitive data types
String Built-in Methods
Object
Object Array
Spread operator to copy [… test1]
Callback function
() ⇒ {} / () ⇒ () function
==(loose equality) vs ===(strict equality)
Function declarations, hoisting
Function: The arguments object
DOM manipulation
Selecting elements
Manipulating elements
Working with Events - Ways to create event
Events Flow - Events Bubbling(default)
Events Flow - Event capturing
Event Object - Properties and Methods
Event Delegation
JavaScript Advanced Topic - Anonymous Functions
JavaScript Advanced Topic - immediately invoked function IIFE /ˈɪfi/
Closure ppt105 -108
Closure + asynchronous
Currying Function

JavaScript 1
JavaScript Advanced Topic - Passing by value(primitive data types)
JavaScript Advanced Topic - Passing by value of object(objects)
call(), apply() and bind()
Promise
Async and await
Event Loop
this

JavaScript vs Java
Java is considered a compiled programming language, while JavaScript is
considered an interpreted scripting language

1. Compiled programming language (e.g., Java):


In a compiled language like Java, the source code is written by the
programmer and then passed through a compiler. The compiler
translates the entire source code into machine code or bytecode, which
is specific to the target platform or architecture. This compiled code is
then executed directly by the computer's hardware or through a virtual
machine (such as the Java Virtual Machine - JVM). The compilation
process happens before the program is run, and any errors are usually
caught during this phase. This approach often leads to faster execution
times but might require separate compilation for different platforms.

2. Interpreted scripting language (e.g., JavaScript):


In an interpreted scripting language like JavaScript, the source code is
executed line-by-line or statement-by-statement at runtime. There is no
separate compilation step. Instead, an interpreter reads the code and
executes it directly. This means that the code is interpreted and
executed on the fly when the program is run. Interpreted languages are
generally more flexible and can be platform-independent, but they
might have slower execution times compared to compiled languages
since they do not undergo a pre-compilation phase.

Java uses static type checking, and JavaScript uses dynamic typing

1. Java - Static Typing:


Java is a statically-typed programming language. In Java,

JavaScript 2
you must declare the data type of a variable explicitly when you
define it. Once the data type is declared, it cannot be changed during
the execution of the program. The Java compiler enforces strong type
checking, meaning it checks for type compatibility at compile-time,
ensuring that only operations that are valid for the declared types are
allowed. If there is a type mismatch or an incompatible operation, the
compiler raises an error, and the program must be fixed before it can be
executed.
Example of static typing in Java:

int age = 30; // Declaration of an integer variable


'age'
String name = "John"; // Declaration of a string vari
able 'name'

// The following line would be valid since age is an


integer, and the addition is allowed for integers.
int result = age + 5;

// The following line would cause a compile-time erro


r since adding a string to an integer is not allowed.
int invalidResult = name + 5;

2. JavaScript - Dynamic Typing:


JavaScript, on the other hand, is a dynamically-typed programming
language. In JavaScript,
you don't need to specify the data type of a variable explicitly.
Variables can hold values of any type, and their types can change
dynamically during runtime. JavaScript performs type checking at
runtime, which means type-related errors may only be discovered while
the program is running. This flexibility can be convenient but also
requires careful handling to avoid unexpected behavior.

Example of dynamic typing in JavaScript:

JavaScript 3
let age = 30; // Declaration of a variable 'age' with
an integer value
let name = "John"; // Declaration of a variable 'nam
e' with a string value

// The following line would be valid since age is an


integer, and the addition is allowed for numbers.
let result = age + 5;

// The following line would not cause any errors in J


avaScript, but it would concatenate the number and th
e string.
let invalidResult = name + 5; // This results in "Joh
n5"

Java uses multiple threads to perform tasks in parallel, whereas JavaScript


handles concurrency on one main thread of execution

1. Java - Concurrency with Multiple Threads:


Java provides built-in support for multithreading, which allows you to
create and manage multiple threads of execution within a single Java
process. Each thread can perform its tasks concurrently, meaning they
can execute independently and potentially in parallel on multi-core
processors. Java's multithreading capabilities are part of the language
and standard library, making it relatively easy to create and manage
threads.
For example, you can use Java's Thread class or the more modern
ExecutorService framework to create and manage threads. By doing so,

you can achieve parallel execution of tasks and take advantage of


multi-core processors to improve performance for certain types of
applications.

2. JavaScript - Concurrency with a Single Main Thread:


JavaScript, particularly in the context of web browsers, is primarily
single-threaded. This means that JavaScript code typically runs on one
main thread of execution, which is often referred to as the "event loop."

JavaScript 4
The event loop is responsible for processing events and executing
asynchronous tasks, such as user interactions, timers, and network
requests.

While JavaScript itself is single-threaded, it can still handle


concurrency through asynchronous programming. JavaScript leverages
callbacks, promises, and async/await to manage asynchronous tasks
efficiently. When an asynchronous task is initiated (e.g., an HTTP
request or a timer), JavaScript doesn't block the main thread but
continues executing other tasks until the asynchronous operation
completes. Once the operation is finished, the associated callback or
promise resolution is added to the event queue, and the event loop
processes it when the main thread is idle.

Java follows class based inheritance, while in JavaScript, inheritance is


prototypal
Java and JavaScript use different approaches for inheritance:

1. Java - Class-Based Inheritance:


Java follows a class-based inheritance model. In Java, you define
classes that serve as blueprints for objects, and objects are instances
of those classes. Classes can be organized into hierarchies, and
inheritance is achieved by creating a new class (a subclass) based on
an existing class (a superclass). The subclass inherits the properties
and behaviors (fields and methods) of the superclass. This allows code
reuse and the ability to extend and modify the behavior of existing
classes.
Example of class-based inheritance in Java:

class Animal {
void makeSound() {
[Link]("Some generic animal so
und.");
}
}

class Dog extends Animal {

JavaScript 5
void makeSound() {
[Link]("Bark!");
}
}

In this example, Animal is the superclass, and Dog is the subclass.


The Dog class inherits the makeSound method from the Animal class,
but it overrides the method to provide its own implementation.

2. JavaScript - Prototypal Inheritance:


JavaScript follows a prototypal inheritance model. In JavaScript,
objects inherit directly from other objects. Every object in JavaScript
has a property called
prototype , which is used to create a prototype chain. When a property
or method is accessed on an object, JavaScript looks for that
property/method in the object itself, and if not found, it looks in the
prototype chain until it finds the property/method or reaches the end of
the chain (where the prototype is null ).
Example of prototypal inheritance in JavaScript:

const animalPrototype = {
makeSound() {
[Link]("Some generic animal sound.");
}
};

const dog = [Link](animalPrototype);


[Link] = function() {
[Link]("Bark!");
};

In this example, animalPrototype serves as the prototype for the dog


object. When makeSound is called on the dog object, JavaScript first
looks for the method in the dog object itself. Since the dog object has
its own makeSound method, it is used instead of the one in animalPrototype .
JavaScript vs Typescript

JavaScript 6
JavaScript (JS) and TypeScript are both languages used for web development,
but they have some important differences:
JavaScript (JS):

1. Standardization: JavaScript is the ECMAScript standardized scripting


language and is widely supported across all web browsers without the
need for any additional tools.

2. Dynamic Typing: It is dynamically typed, which means you can change the
type of a variable at runtime and the interpreter won't know the type of the
variable until the code is running.

3. Ecosystem: JavaScript has a massive ecosystem with a huge number of


libraries and frameworks (like React, Vue, and Angular) to aid in
development for both client-side and server-side ([Link]).

4. Learning Curve: JavaScript, as a language, is usually easier to start with


for beginners because it has fewer concepts to grasp initially and is the de
facto language of the web.

5. Flexibility: It can be very flexible, but this can also lead to less predictable
code, which might be full of surprises due to its dynamic nature.

TypeScript:

1. Superset of JavaScript: TypeScript is a superset of JavaScript. This means


that any valid JavaScript code is also valid TypeScript code.

2. Static Typing: TypeScript adds optional static typing to the language.


Types can be explicitly assigned to variables, functions, properties, etc.
This can catch potential bugs at compile-time rather than at runtime.

3. Tooling: The type system allows for better tooling, including more powerful
autocomplete, navigation, and refactoring features.

4. Compilation: TypeScript code needs to be compiled to JavaScript before it


can be run in browsers or on the [Link] platform. This is typically done
using the TypeScript compiler (tsc) or through build tools like Webpack or
Babel.

5. Readability and Maintainability: The explicit types and interfaces can


make the code more readable and easier to maintain, especially for large

JavaScript 7
codebases or teams.

6. Learning Curve: TypeScript has a steeper learning curve, especially for


developers not familiar with type systems. However, those coming from
statically typed languages may find TypeScript more comfortable.

7. Community and Adoption: TypeScript has been rapidly gaining in


popularity, especially in the enterprise sector, and many popular JavaScript
frameworks support TypeScript out of the box.

8. Error Catching: TypeScript’s type system helps catch errors early in the
development process, which can lead to more robust, cleaner code.

In summary, TypeScript is designed to develop large applications and transpile


down to JavaScript. It provides typing and compile-time verification which can
potentially lead to higher quality codebase. JavaScript, being the core
language of the web, is universal but lacks the features to easily manage the
complexity of large-scale applications without the help of additional tools or
frameworks.
Babel
babel configuration

Babel is a JavaScript compiler that lets you use ES6+ code in older
browsers. It's commonly used in modern web development projects to
ensure compatibility across different browsers. To configure Babel, you
typically work with a .babelrc file (or [Link] in more recent
versions). Here's a brief guide to setting up and configuring Babel:

1. Installing Babel:
If you're starting from scratch, you'll want to set up a new project with
npm:

mkdir my-new-project && cd my-new-project


npm init -y

Now, install Babel and its CLI:

npm install --save-dev @babel/core @babel/cli

JavaScript 8
2. Babel Presets & Plugins:
Babel uses "presets" and "plugins" to determine how to transform your
code. A preset is a set of plugins bundled together.
For example, to transform ES6+ code to ES5:

npm install --save-dev @babel/preset-env

Then, create a .babelrc file (or [Link] ) in the root of your


project and add:

{
"presets": ["@babel/preset-env"]
}

3. Transforming Code:

With the CLI installed and the preset set, you can now compile your
ES6+ code:

npx babel src --out-dir dist

This command will take the JavaScript files from the src directory and
compile them to ES5 in the dist directory.

4. React Configuration:

If you're using React, you'll want to add the Babel preset for React:

npm install --save-dev @babel/preset-react

Then, add it to your .babelrc :

{
"presets": ["@babel/preset-env", "@babel/preset-rea

JavaScript 9
ct"]
}

5. Other Configurations:

You might come across the need for other plugins or presets based on
what features you're using. For instance, if you want to use
async/await, you might need the @babel/plugin-transform-runtime and
@babel/runtime .
Always refer to the Babel documentation or specific plugin/preset
documentation for additional setup details.

6. Babel with Webpack, Rollup, etc.:

If you're using a module bundler like Webpack or Rollup, they have their
own Babel integrations, like babel-loader for Webpack. This lets you
integrate Babel into the bundling process.

Remember, Babel's primary function is to transform newer JS syntax into


older syntax for broader compatibility. It doesn't polyfill missing APIs (like
[Link] or ), so you might also want to look into
[Link]

something like core-js or @babel/polyfill (deprecated in Babel 7.4.0 in favor


of directly including core-js/stable and regenerator-runtime/runtime for
generator functions).
Lastly, Babel configurations can also reside within the [Link] under
the "babel" key if you prefer to keep configurations centralized.

Babel is a widely used JavaScript compiler that allows you to write JavaScript
code using the latest ECMAScript features and then transpile (convert) that
code into an older version of JavaScript that is compatible with most browsers
and environments. This is particularly useful because it allows developers to
take advantage of new language features without worrying about whether they
are supported in all browsers.

Here are the steps to set up a JavaScript application with Babel:

1. Initialize Your Project:


You'll need to create a new directory for your project and navigate to it in

JavaScript 10
your terminal. Then, you can initialize a new [Link] project if you haven't
already by running:

npm init -y

2. Install Babel Dependencies:


Next, you need to install Babel and its plugins. The main Babel package is
called
@babel/core , and you'll also need presets to specify which versions of

JavaScript you want to support. One common preset is @babel/preset-env ,


which can automatically determine which features to transpile based on
your specified target environments. You can install these packages using
npm:

npm install @babel/core @babel/preset-env --save-dev

3. Create a Babel Configuration File:


Create a
.babelrc configuration file in the root of your project. This file tells Babel

how to transpile your code. For example:

{
"presets": ["@babel/preset-env"]
}

4. Write Your JavaScript Code:


Write your JavaScript code using the latest ECMAScript features in a file,
such as
[Link] .

5. Transpile Your Code:


To transpile your code, you can use Babel's command-line interface (CLI)
or integrate it into your build process. If you're using the CLI, you can run a
command like this to transpile your code:

JavaScript 11
npx babel [Link] -o [Link]

This command transpiles [Link] into [Link] .

6. Include the Transpiled Code in Your HTML:


In your HTML file, include the transpiled JavaScript file,
[Link] , which contains the code that is compatible with most browsers:

<script src="[Link]"></script>

7. Build Process (Optional):


For larger projects, you might want to set up a build process using tools like
Webpack, Gulp, or Grunt to automate the transpilation and other tasks. This
helps streamline development and deployment.

8. Testing and Running Your Application:


Finally, you can test and run your application as usual, and it should work in
a wide range of browsers thanks to Babel's transpilation.

Babel is a powerful tool for modern JavaScript development, and it can greatly
improve your ability to write code using the latest language features while
maintaining compatibility with older browsers.
Webpack
Webpack is a static module bundler for JavaScript applications. When
Webpack processes your application, it internally builds a dependency graph
which maps every module your project needs and generates one or more
bundles. Over the years, Webpack has grown and can now transform front-end
assets like HTML, CSS, and images, if the corresponding plugins are included.

Here are some core concepts and features of Webpack:


Webpack is an open-source JavaScript module bundler. It's primarily used
for bundling JavaScript files for usage in a browser, but it is also capable of
transforming, bundling, or packaging just about any resource or asset.
Webpack takes modules with dependencies and generates static assets
representing those modules.
Here are some core concepts and features of Webpack:

JavaScript 12
1. Entry
An entry point indicates which module Webpack should use to begin
building out its internal dependency graph. Webpack will figure out which
other modules and libraries that entry point depends on (directly and
indirectly).

[Link] = {
entry: './path/to/my/entry/[Link]'
};

2. Output
The output property tells Webpack where to emit the bundles it creates and
how to name these files. It defaults to ./dist/[Link] for the main output file
and to the ./dist folder for any other generated file.

[Link] = {
output: {
filename: '[Link]',
path: __dirname + '/dist'
}
};

3. Loaders
Webpack only understands JavaScript and JSON files. Loaders allow
Webpack to process other types of files and convert them into valid
modules that can be consumed by your application and added to the
dependency graph.

[Link] = {
module: {
rules: [
{ test: /\\.txt$/, use: 'raw-loader' },
{ test: /\\.css$/, use: ['style-loader', 'css-load
er'] },

JavaScript 13
// and so on for other file types like .scss, .les
s, .ts, etc.
]
}
};

4. Plugins
While loaders are used to transform certain types of modules, plugins can
be leveraged to perform a wider range of tasks like bundle optimization,
asset management, and injection of environment variables.

const HtmlWebpackPlugin = require('html-webpack-plugi


n');

[Link] = {
plugins: [new HtmlWebpackPlugin({ template: './src/ind
[Link]' })]
};

5. Mode
By setting the mode parameter to either development , production , or none , you
can enable Webpack's built-in optimizations that correspond to each
environment.

[Link] = {
mode: 'production'
};

6. DevServer
Webpack provides a development server that can be used to quickly
develop applications. It provides live reloading out of the box, among other
features.

JavaScript 14
[Link] = {
devServer: {
contentBase: './dist',
hot: true
}
};

7. Source Maps
Webpack can generate source maps, which is a way to map your compiled
code back to your original source code. This is extremely helpful for
debugging your application.

[Link] = {
devtool: 'inline-source-map'
};

8. Code Splitting
Webpack allows you to split your codebase into multiple chunks. Code
splitting can be used to load parts of the application on demand and can
significantly improve performance.

9. Tree Shaking
This is a feature provided by Webpack that is used to remove unused code
from your bundle, helping to keep the bundle size down.

10. Environment Variables


Webpack allows you to configure environment-specific settings in your
application by using environment variables.
Webpack has a lot of other advanced features and can be configured to
handle complex application needs. Its powerful API and rich ecosystem of
loaders and plugins make it a flexible tool that can handle a wide array of
web development tasks.

JavaScript 15
Here's a basic guide to setting up and configuring Webpack:

1. Installing Webpack:

Initialize a new npm project (if you haven't):

mkdir my-webpack-project && cd my-webpack-project


npm init -y

Install Webpack and its CLI:

npm install --save-dev webpack webpack-cli

2. Basic Configuration:

Create a file named [Link] in the root of your project:

const path = require('path');

[Link] = {
mode: 'development',
entry: './src/[Link]',
output: {
filename: '[Link]',
path: [Link](__dirname, 'dist'),
},
};

This configuration tells Webpack:

mode: The mode (either "development" or "production"). Each mode


has its own default configurations.

entry : The entry point of your application.

output : Where to emit the bundles it creates and how to name them.

3. Loaders:

JavaScript 16
Loaders allow Webpack to process other types of files and convert them
into valid modules.

For example, to handle CSS, you'd use css-loader to interpret @import and
url() and style-loader to inject CSS into the DOM:

npm install --save-dev css-loader style-loader

Then, modify [Link] :

module: {
rules: [
{
test: /\\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},

4. Plugins:
Plugins can be leveraged to perform a wider range of tasks like bundle
optimization, asset management, and injection of environment variables.
For instance, to manage HTML files, you can use html-webpack-plugin :

npm install --save-dev html-webpack-plugin

Update [Link] :

const HtmlWebpackPlugin = require('html-webpack-plugi


n');

//...

plugins: [new HtmlWebpackPlugin({template: './src/index.


html'})],

JavaScript 17
5. Dev Server:

Webpack provides a development server that can be used to serve your


application during development.

npm install --save-dev webpack-dev-server

Update [Link] :

devServer: {
contentBase: './dist',
},

Then, you can run the dev server using:

npx webpack serve

6. Other Configurations:

Source Maps: Helpful for debugging. Can be enabled with devtool:

'inline-source-map' .

Code Splitting: Helps in splitting code into various bundles for


optimization.

Environment Variables: DefinePlugin can be used to set environment


variables.

Always refer to the official Webpack documentation for deeper dives into
configurations and setups. The ecosystem is vast, and there are loaders,
plugins, and configurations for many common use cases.
Prototype
In JavaScript, the prototype is an inherent property of every object. It is a
mechanism that allows objects to inherit properties and methods from other
objects.
The prototype is itself an object, so the prototype will have its own prototype,
making what's called a prototype chain . The chain ends when we reach a
prototype that has null for its own prototype.

JavaScript 18
When you try to access a property of an object: if the property can't be found
in the object itself, the prototype is searched for the property. If the property
still can't be found, then the prototype's prototype is searched, and so on until
either the property is found, or the end of the chain is reached, in which
case undefined is returned.
ES5 vs ES6

1. Variable Declaration: Let & Const (Block Scope vs. Function


Scope)
ES5: Only has var which is function-scoped.

function example() {
if (true) {
var x = 5;
}
[Link](x); // outputs 5
}

ES6: Introduces let and const which are block-scoped.

function example() {
if (true) {
let y = 5;
const z = 10;
}
[Link](y); // ReferenceError: y is not defined
[Link](z); // ReferenceError: z is not defined
}

2. Arrow Functions
ES5: Functions are typically written using the function keyword.

ES6: Introduces arrow functions.

JavaScript 19
// ES5
var add = function(x, y) {
return x + y;
};

// ES6
const add = (x, y) => x + y;

3. Promises
ES5: Callbacks were predominantly used for asynchronous operations.

ES6: Introduces Promises as a way to handle asynchronous operations.

4. Classes
ES5: In ES5, developers emulated class-like behavior using constructor
functions and prototypes.

ES6: Introduces class syntax as syntactic sugar.

// ES5
function Car(make) {
[Link] = make;
}
[Link] = function() {};

// ES6
class Car {
constructor(make) {
[Link] = make;
}
drive() {}
}

4. Enhanced Object Literals

JavaScript 20
ES6 introduces shorthand for property methods and defines properties.

let prop = "value";


let obj = {
prop,
["a" + "b"]: "computed property names",
method() {
[Link]("Shorthand method");
}
};

5. Template Literals
ES5: In ES5, developers concatenated strings using the + operator.

ES6: ES6 introduced template literals with backticks, allowing embedded


expressions inside string literals.

// ES5
var str = "Hello, " + name + "!";

// ES6
let str = `Hello, ${name}!`;

6. Default + Spread + Rest Parameters


ES6 introduces default parameters, spread operator, and rest parameters.

function example(x=1, ...args) {


[Link](args); // logs an array of arguments ex
cluding x
}
example(1, 2, 3, 4); // logs [2, 3, 4]

let arr1 = [1, 2, 3];


let arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

JavaScript 21
7. Destructuring
ES6 introduces destructuring assignment.

let {a, b, ...rest} = {a: 1, b: 2, c: 3, d: 4};


[Link](a); // 1
[Link](rest); // {c: 3, d: 4}

8. Modules
ES5: No native module system. Relied on third-party solutions like
CommonJS or AMD.

ES6: Introduces native modules using import and export .

10. New Built-in Methods and Objects


ES6 introduces many new methods on existing built-in objects and even
new objects like Map , Set , WeakMap , WeakSet , and Symbol .

11. Iterators and Generators


ES6 introduces the new for...of loop, iterators, and generator functions.

12. Enhanced Unicode Support


ES6 has better support for Unicode characters, including the ability to use
Unicode code points for characters outside the Basic Multilingual Plane
(BMP).

There are many other improvements and additions in ES6 compared to ES5.
These differences mark a significant evolution of the language, making
JavaScript more powerful and developer-friendly.
JavaScript Variables: Global and local variables
In JavaScript, all variables exist within a scope that determines the lifetime of
the variables and which part of the code can access them.
Scope determines the accessibility (visibility) of variables.

JavaScript has 3 types of scope:

JavaScript 22
Block scope

Function scope

Global scope

Before ES6 (2015), JavaScript had only Global Scope and Function Scope for
var .

Block scope

ES6 introduced two important new JavaScript


keywords: let and const . These two keywords
provide Block Scope in JavaScript.

Variables let declared inside a { } (curly brackets) block cannot be


accessed from outside the block:

{
let x = 2;
}
// x can NOT be used here

However:

Variables declared with the var keyword can NOT have block scope.
Variables declared inside a { }(curly brackets) block can be accessed from
outside the block.

{
var x = 2;
}
// x CAN be used here

Local scope
Variables declared within a JavaScript function, become LOCAL to the
function. Local variables have Function Scope. They can only be accessed

JavaScript 23
from within the function.

// code here can NOT use carName

function myFunction() {
let carName = "Volvo";
// code here CAN use carName
}

// code here can NOT use carName

Since local variables are only recognized inside their functions, variables
with the same name can be used in different functions.
Local variables are created when a function starts, and deleted when the
function is completed.

Function scope

If you declare a variable in a function, JavaScript adds the


variable to the function scope .

Each function creates a new scope.

Variables defined inside a function are not accessible (visible) from


outside the function.

Variables declared with var , let and const are quite similar when declared
inside a function. They all have Function Scope:

function myFunction() {
var carName = "Volvo"; // Function Scope
}

function myFunction() {
let carName = "Volvo"; // Function Scope
}

JavaScript 24
function myFunction() {
const carName = "Volvo"; // Function Scope
}

Global Scope

If you declare a variable outside of a function, JavaScript


adds it to the global scope .

Variables declared Globally (outside any function) have Global Scope.


Global variables can be accessed from anywhere in a JavaScript
program.
Variables declared with var , let and const are quite similar when declared
outside a block. They all have Global Scope:

var x = 2; // Global scope


let x = 2; // Global scope
const x = 2; // Global scope

JavaScript Variables: Variable shadowing


when a variable is declared in a certain scope having the same name defined
on its outer scope and when we call the variable from the inner scope, the
value assigned to the variable in the inner scope is the value that will be stored
in the variable in the memory space. This is known as Shadowing or Variable
Shadowing.
In JavaScript, the introduction of let and const in ES6 along with block scoping

allows variable shadowing.

var along with function scoping allows variable shadowing.

Variable Shadowing with var

Variable shadowing occurs when a variable declared in an inner scope has


the same name as a variable in an outer scope. The inner variable
"shadows" the outer one, making it inaccessible for the duration of the
inner scope.

JavaScript 25
With the var keyword in JavaScript, variable shadowing can occur, but
there's a unique behavior to consider. Variables declared with var are
function-scoped, not block-scoped. This means that a variable declared
with var inside structures like for loops or if statements doesn't create a
new scope, unlike variables declared with let or const .
Here's an example of shadowing using var :

var x = 10; // outer scope variable

function exampleFunction() {
var x = 20; // inner scope variable, shadows the outer
x
[Link](x); // This will output 20, not 10
}

exampleFunction();
[Link](x); // This will output 10

In this example, the x inside exampleFunction shadows the outer x .

However, consider this:

var x = 10;

if (true) {
var x = 20; // Despite being inside an if statement, t
his is in the same scope as the outer x
[Link](x); // This will output 20
}

[Link](x); // This will also output 20, not 10

In the above example, even though x is re-declared and assigned inside an


if statement, due to the function-scoping behavior of var , it essentially

overwrites the outer x . This is one of the potential pitfalls of using var , and

JavaScript 26
a reason many developers have moved to using let and const , which
provide block-level scoping.

For example, we have two variables that share the same name: message. The
first message variable is a global variable whereas the second one is the local
variable. Inside the say() function, the global message variable is shadowed. It
cannot be accessible inside the say() function but outside of the function. This
is called variable shadowing.

// global variable
var message = "Hello";

function say() {
// local variable
var message = 'Hi’;
[Link](message);
// which message?
}

say();// Hi
[Link](message); // Hello

JavaScript Variables: Non-strict mode


In non-strict mode, if a variable is used without being explicitly declared with
the var , let , or const keyword, it becomes an implicit global variable.
In non-strict mode, you can use a variable without declaring it first, which can
lead to unexpected behavior if you mistype the variable name. In strict mode,
however, using an undeclared variable will throw a reference error.
To avoid creating a global variable accidentally inside a function because of
omitting the var keyword, you use the strict mode by adding the "use strict"; at
the beginning of the JavaScript file (or the function).

JavaScript 27
In this code, the message variable is not explicitly declared, so it becomes a
global variable. That's why it is accessible both inside and outside the say()
function, and its value is retained after the function call.

function say() {
message = 'Hi’;
[Link](message);
// which message?
}
say();// Hi
[Link](message); //Hi

JavaScript Variables: strict mode


Strict mode is a subset of JavaScript that provides better error checking and
enforces stricter rules for coding. It was introduced in ES5. When strict mode
is enabled, the JavaScript engine checks for syntax errors and runtime
errors that would otherwise go unnoticed in non-strict mode. This makes it
easier for developers to catch errors early in the development process,
resulting in fewer bugs and better code quality.

JavaScript Variables: hoisting


Hoisting is a mechanism/ˈmekənɪzəm/ that the JavaScript engine moves all the
variable declarations to the top of their scopes in the parsing phase, either
function or global scopes.
This means that you can use variables and call functions before their actual
declarations in the code, and they will still be recognized. However, only the
declarations are hoisted, not the initializations or assignments. The variables
are initialized with the value undefined until their actual assignment is
encountered during the execution phase.
But it only works for var .
Using a let variable before it is declared will result in a ReferenceError .

[Link](x); // Output: undefined


var x = 5; // Variable 'x' is hoisted to the top of the

JavaScript 28
// Equivalent to:
// var x;
// [Link](x);
// x = 5;

When executing JavaScript code, the JavaScript engine goes through two
phases:

Parsing/ˈpɑːrsɪŋ/

Execution

In the parsing phase, the JavaScript engine moves all variable/ˈveriəb(ə)l/


declarations to the top of the file if the variables are global, or to the top of a
function if the variables are declared in the function.

The let and const Keywords X


Variables defined with let and const are hoisted to the top of the block ,
but not initialized .
Meaning: The block of code is aware of the variable, but it cannot be used
until it has been declared.
Using a let variable before it is declared will result in a ReferenceError .
The variable is in a "temporal dead zone" from the start of the block until it
is declared.
JavaScript Variables: var, let, const
var

The var keyword has been available in JavaScript since its early versions.

Scope: Global scoped or function scoped. The scope of


the var keyword is the global or function scope. It means variables
defined outside the function can be accessed globally, and variables
defined inside a particular function can be accessed within the
function.

The user can re-declare(reassign) the variable using var and the user
can update the var variable.

JavaScript 29
var a = 10

// User can re-declare


// variable using var
var a = 8

// User can update var variable


a = 7

// Output: 7

var variables are also hoisted (meaning they are moved to the top of
their scope during the execution phase).If users use the var variable
before the declaration, it initializes with the undefined value.

[Link](a); // undefined
var a = 10;

let

Scope: block scoped: The scope of a let variable is only block scoped.
It can’t be accessible outside the particular block ({block}).

From ES6, you can use the let keyword to declare one
or more variables. The let keyword is similar to the
var keyword. However, a variable is declared using the
let keyword is block-scoped, not function or global-
scoped like the var keyword.

Users cannot re-declare the variable defined with the let keyword but
can update it.

1. Users cannot re-declare the variable defined with the let

keyword: If a variable has already been declared using let within

JavaScript 30
the same scope, you cannot declare it again with let (or const ).
Doing so will result in a syntax error.

let example = "first declaration";


let example = "second declaration"; // SyntaxErro
r: Identifier 'example' has already been declared

2. Users can update it: Variables declared with let are mutable,
meaning their values can be changed after they've been initialized.

let example = "original value";


[Link](example); // Outputs: "original value"

example = "updated value";


[Link](example); // Outputs: "updated value"

If users use the let variable before the declaration, it does not initialize
with undefined just like a var variable, and returns an error.

const

Scope: block scoped: When users declare a const variable, they need
to initialize it, otherwise, it returns an error. The user cannot update
the const variable once it is declared.

The const keyword has all the properties that are the same as
the let keyword, except the user cannot update it. cannot re-declare

Constant Objects and Arrays


Users cannot change the properties of the const object, but they can
change the value of the properties of the const object. (You can modify and
you can’t reassign.)

const a = {
prop1: 10,
prop2: 9

JavaScript 31
}

// It is allowed
a.prop1 = 3

// It is not allowed
a = {
b: 10,
prop2: 9
}

// Output: Uncaught SyntaxError:Unexpected identifier

var let const

The scope of
The scope of a let variable is The scope of a const variable
a var variable is
block scope. is block scope.
functional scope.

It can be updated
It can be updated but cannot It cannot be updated or re-
and re-declared
be re-declared into the scope. declared into the scope.
into the scope.

It can be declared
It can be declared without It cannot be declared without
without
initialization. initialization.
initialization.

It can be accessed
It cannot be accessed without It cannot be accessed without
without initialization
initialization otherwise it will initialization, as it cannot be
as its default value
give ‘referenceError’. declared without initialization.
is “undefined”.

Hoisting is done, but not Hoisting is done, but not


hoisting done, with initialized (this is the reason for initialized (this is the reason for
initializing as the error when we access the the error when we access the
‘default’ value let variable before const variable before
declaration/initialization declaration/initialization

Primitive data types

JavaScript 32
JavaScript has six primitive data types:
• null
• undefined
• boolean
• number
• string
• symbol – available only from ES6

• object - One complex data type called object

Immutable

Primitive values are immutable (they are hardcoded and


cannot be changed). if x = 3.14, you can change
the value of x, but you cannot change the value of 3.14.

undefined
The undefined type is a primitive type that has one value undefined.
By default, when a variable is declared but not initialized, it is assigned the
value undefined.

let counter;
[Link](counter); // undefined
[Link](typeof counter); // undefined

null
The null type is the second primitive data type that also has only one value:
null

When using the typeof operator on null , it returns 'object'

let obj = null;


[Link](typeof obj); // object

number

JavaScript 33
• Integer numbers
• Floating-point numbers
• NaN: which stands for Not a Number. In fact, it means an invalid number

let num = 100;


let pi = 3.14;

typeof num // number


[Link]('a'/2); // NaN;

Question: what is the result of 0.1 + 0.2 ?

The result is not 0.3 !

The actual result is 0.30000000000000004

We can use the following method to get the accuracy


[Link](1)

FYI: toFixed()’s type of return value should be string, and


you can use Number to convert it to number.

[Link](Number(0.1 + 0.2).toFixed(1));

String
In JavaScript, a string is a sequence of zero or more characters. A literal
string begins and ends with either a single quote(‘) or a double quote (“).
You can use literals `` to represent string as well.

let greeting = 'Hi’;


let s = "It's a valid string";
let str = ‘I\’m also a string‘; // use \ to escape the sin

JavaScript 34
Let greeting = `HI`
let message = `Hello ${name}`;

Boolean
The boolean type has two values: true and false, in lowercase.
To convert a value of another data type into a boolean value, you use the
Boolean function.

[Link](Boolean('Hi'));// true

String Built-in Methods


trim()

trim()/trɪm/ returns a new string stripped of whitespace characters from


beginning and end of a string. It does not modify the original string;
instead, it creates and returns a new string.

To remove whitespace characters from the beginning or from the end of a


string only, you use the trimStart() or trimEnd() method.

let inputValue = [Link]();


// It does not modify the original string;
// Instead, it creates and returns a new string.

indexOf()

indexOf() returns the index of the first occurrence of substring (substr) in a


string(str). And we have the same built-in method in Array.
The indexOf() always perform a case-sensitive search.
To perform a case-insensitive search for the index of a substring within a
string, you can convert both substring and string to lowercase before using
the indexOf() method.

let index = [Link](substr, fromIndex); // starting se


let index = [Link]().indexOf([Link]

split()

JavaScript 35
split() divides a string into an array of substrings:

split([separator], [limit]);

Example we want to split the string by comma or space


We could take the advantage of using regex(regular expression) in
separator

const test = "abf,3er ert";


let array = [Link](/[ ,]/);

// Returning a limited number of substrings


let array = [Link](/[ ,]/, 2);

includes()

The includes() method determines whether a string contains another string.


Return true or false.

[Link](searchString [,position])

let email = 'admin@[Link]’;


[Link]([Link]('@'));

slice()

The slice() method returns a substring from the startIndex to the endIndex
in the str
FYI, [startIndex, endIndex), the startIndex is inclusive, and the endIndex is
exclusive. We have the same built-in methods in Array.

let substr = [Link](startIndex, endIndex);

Object
In JavaScript, an object is a collection of properties, where each property is
defined as a key-value pair.

JavaScript 36
The following example defines an empty object using the object literal form:

let emptyObject = {}; // braces/ˈbreɪsɪz/ {}

The example defines the person object with two properties:

let person = {
firstName: 'John’,
lastName: 'Doe’
};

Object attribute rule

A property name of an object can be any string. You can use quotes around
the property name if it isn’t a valid JavaScript identifier.
For example, if you have a property first-name, you must use the quotes
such as "first-name" but firstName is a valid JavaScript identifier so the
quotes are optional.
If you refer to a non-existent property, you’ll get an undefined value as
follows:

[Link]([Link]); // undefined

Object operations
要操作对象中的信息,您可以使用以下方式:
1. 访问属性

使用点符号 .

[Link]([Link]); // 输出: John


[Link]([Link]); // 输出: Doe
或者使用方括号 与字符串形式的属性名:
[]

[Link](person['firstName']); // 输出: John

JavaScript 37
[Link](person['lastName']); // 输出: Doe

2. 修改属性的值
直接为属性分配一个新值:
[Link] = 'Jane';
[Link]([Link]); // 输出: Jane

使用方括号 [] :

person['lastName'] = 'Smith';
[Link]([Link]); // 输出: Smith

3. 添加新属性
如果你尝试为对象中尚不存在的属性分配值,JavaScript 会为该对象创建该
属性:
[Link] = 30;
[Link]([Link]); // 输出: 30

同样,使用方括号 也可以: []

person['job'] = 'Engineer';
[Link]([Link]); // 输出: Engineer

4. 删除属性
使用 关键字:
delete

delete [Link];
[Link]([Link]); // 输出: undefined

5. 检查属性是否存在
使用 关键字:
in

JavaScript 38
if ('firstName' in person) {
[Link]('The person has a first name.');
}

6. 遍历对象的属性
使用 循环:
for...in

for (let key in person) {


[Link](key, person[key]);
}

这些基本操作为您提供了处理和操作对象数据的方法。
create object

1. Using the JavaScript Keyword new


create a new JavaScript object using new Object()

const person = new Object();


[Link] = "John";
[Link] = "Doe";
[Link] = 50;
[Link] = "blue";

2. Using an Object Literal


Using an object literal, you both define and create an object in one
statement.

An object literal is a list of name:value pairs (like age:50) inside curly


braces {}.

const person = {
firstName: "John",
lastName: "Doe",
age: 50,

JavaScript 39
eyeColor: "blue"
};

Object Array
Two ways to create an array

1. use the Array constructor new Array()

let scores = new Array();

// If you know the number of elements that the array wi


// you can create an array with an initial size:
let scores = new Array(10);

2. use the Array literal notation

let arrayName = [element1, element2, element3, ...]; //

Accessing JavaScript array elements

arrayName[index]

Getting the array size, using the length property

[Link]

Adding an element to the end of an array

[Link]('Red Sea’);

The push() method modifies the original array by adding


the element 'Red Sea' to the end of the array. It mutates
the existing arrayName array. It returns the new length of

JavaScript 40
the modified array. The reference to arrayName remains the
same, but the array itself is modified.
Adding an element to the end of an array(ES6 Syntax)

arrayName = […arrayName, 'Red Sea’]

This approach uses the spread operator ( ... ) to create a


new array by spreading the elements of the original
arrayName and adding 'Red Sea' as a new element. It

maintains the immutability of the original array, meaning it


doesn't modify the existing arrayName but creates a new
array with the additional element. This approach returns
a new array as the result of the operation. The variable
now references the new array with the additional
element.

Adding an element to the beginning of an array

[Link]('Red Sea’);

Removing an element from the end of an array and return that removed
element

[Link]();

Removing an element from the beginning of an array and return that


removed element

[Link]();

Check if an value is an array

JavaScript 41
[Link](seas);

Finding an index of an element in the array, or -1 if the element is not found.

[Link]('Red Sea’);

splice()
Deleting elements using JavaScript Array’s splice() method
Inserting elements using JavaScript Array splice() method
Note that the splice() method actually changes the original array. Also, the
splice() method does not remove any elements, therefore, it returns an
empty array

[Link](position, num);

[Link](position, 0 ,new_element_1,new_element_2,

// Replacing elements using JavaScript Array splice() meth


let languages = ['C', 'C++', 'Java', 'JavaScript’];
[Link](1, 1, 'Python'); // C++ Python 换成
slice()
The [Link] object provides the slice() method that allows you to
extract subset elements of an array and add them to the new array
Returns a new array containing a shallow copy of a portion of the original
array.
The slice() method accepts two optional parameters as follows:
slice(start, stop); // Both start and stop parameters are optional.
FYI: [start, stop). The slice() returns a new array, it doesn’t change the
source array

// 1. Clone an array
[Link]();

JavaScript 42
// ES6 Syntax:
const newNumbers = [… numbers];

// 2. Copy a portion of an array


const colors = ['red','green','blue','yellow','purple’];
const rgb = [Link](0,3);

every()
Checking every array element meet requirements, return true / false

[Link]((ele, index, numbers) => {


return ele > 0;
});

// Caution: Empty arrays:


// the method will always return true for any condition

some()
Checking at least one elements meet requirements, return true / false

[Link]((ele, index, numbers) => {


return ele > 0;
});

// Caution: Empty arrays:


// the method will always return false for any condition

forEach()
execute a function on every element of an array, no return
What is the difference between for loop and forEach ?

forEach() will iterate over all elements of the array without


providing a way to break out of the loop prematurely.

JavaScript 43
Once you start iterating with forEach() , it will continue to
iterate over all elements in the array until it reaches the
end. Additionally, with
forEach() , you cannot specify a starting index. It always

starts iterating from the first element of the array and


continues until the last element.

[Link]((ele, index, numbers) => {


// code here
});

const names = ['Alice', 'Bob', 'Charlie', 'Dave'];

[Link]((name, index, array) => {


[Link](`Name: ${name}, Index: ${index}, Array: ${ar
});

Output:
Name: Alice, Index: 0, Array: Alice,Bob,Charlie,Dave
Name: Bob, Index: 1, Array: Alice,Bob,Charlie,Dave
Name: Charlie, Index: 2, Array: Alice,Bob,Charlie,Dave
Name: Dave, Index: 3, Array: Alice,Bob,Charlie,Dave

element represents the current element being processed in the iteration.

index represents the index of the current element being processed.

array refers to the array on which the forEach() method was called.

map()
Transform its elements and include the results in a new array.
What is the difference between for map and forEach ?

JavaScript 44
map() will return a new array; forEach() does not return a
value.

[Link]((ele, index, numbers) => {


// code here
});

const numbers = [1, 2, 3, 4, 5];

const multipliedNumbers = [Link]((number) => {


return number * 2;
});

[Link](multipliedNumbers); // Output: [2, 4, 6, 8, 10

!!!reduce()
The reduce() method in JavaScript is used to reduce an array to a single
value by executing a provided callback function on each element of the
array. It accumulates the result of the callback function on each iteration
and returns the final accumulated value.

[Link](callback, initialValue);

const numbers = [1, 2, 3, 4, 5];

const sum = [Link]((accumulator, currentValue, ind


return accumulator + currentValue;
}, 0);

[Link](sum); // Output: 15

*!!!*How to implement a reducer by your own code ?

JavaScript 45
// 1.
[Link] = function (callback, init
let accumulator = initialValue === undefined ? 0 : in

for (let i = 0; i < [Link]; i++) {


accumulator = callback(accumulator, this[i], i, thi
}

return accumulator;
};

const numbers = [1, 2, 3, 4, 5];

const sum = [Link]((accumulator, current)


return accumulator + current;
}, 0);

[Link](sum); // Output: 15

// 2.
const customReducer = (array, callback, initValue) => {
let accumulator = initValue === undefined ? 0 : ini
for (let i = 0; i < [Link]; i++) {
accumulator = callback(accumulator, array[i], i
}
return accumulator;
};

const numbers = [1, 2, 3, 4, 5];

const sum = customReducer(numbers, (accumulator, curren


return accumulator + current;
}, 0);

JavaScript 46
[Link](sum); // Output: 15

filter()
filter() is used to create a new array containing elements from the original
array that satisfy a specified condition. It iterates over the array and applies
a callback function to each element, returning a new array with the
elements for which the callback function returns true .
Will return a new array

numbersfilter((ele, index, numbers) => {


return ele > 0;
});

const numbers = [1, 2, 3, 4, 5];

const evenNumbers = [Link]((number) => {


return number % 2 === 0;
});

[Link](evenNumbers); // Output: [2, 4]

join()
Array join() method to concatenate all elements of an array into a string
separated by a separator

const fruits = ['apple', 'banana', 'cherry'];

const joinedString = [Link](', ');

[Link](joinedString); // Output: "apple, banana, cher

Using the JavaScript Array join() method to replace all occurrences of a


string

JavaScript 47
const title = ' JavaScript array join example ';
const url = [Link]().split(' ').join('-').toLowerCase(
[Link](url); // javascript-array-join-example

Spread operator to copy [… test1]


use spread operator to copy, it creates a new reference to the elements or
properties rather than copying the memory address.
The spread operator is a powerful feature introduced in ECMAScript 6 (ES6)
that allows you to expand elements from arrays, objects, or iterable objects into
various contexts. The spread operator is denoted by three dots ( ... ) and is
used in different contexts to perform specific operations.

1. Array Spread:

When used with an array, the spread operator can expand the elements of the
array into individual elements. It is commonly used to create shallow copies of
arrays , concatenate /kənˈkæt(ə)nˌeɪt/ arrays , or pass array elements as individual

arguments to a function .
Example:

const arr1 = [1, 2, 3];


const arr2 = [4, 5, 6];

const combinedArray = [...arr1, ...arr2];


[Link](combinedArray); // Output: [1, 2, 3, 4, 5, 6]

Creating Shallow Copies of Arrays:


it creates new instances with a new memory address.

const originalArray = [1, 2, 3, 4, 5];

//Creating a shallow copy of the original array using th


e spread operator
const shallowCopy = [...originalArray];

JavaScript 48
[Link](originalArray); // Output: [1, 2, 3, 4, 5]
[Link](shallowCopy); // Output: [1, 2, 3, 4, 5]

// Modifying the shallow copy will not affect the origin


al array
[Link](6);
[Link](originalArray); // Output: [1, 2, 3, 4, 5]
[Link](shallowCopy); // Output: [1, 2, 3, 4, 5,
6]

shallow copies

When using the spread operator to create shallow copies of arrays or


objects, it creates new instances with a new memory address. This
means that the original array or object and the shallow copy are two
distinct objects stored in separate memory locations.
Let's clarify this with examples:

1. Creating Shallow Copies of Arrays:

const originalArray = [1, 2, 3, 4, 5];

// Creating a shallow copy of the original array usin


g the spread operator
const shallowCopy = [...originalArray];

[Link](originalArray); // Output: [1, 2, 3, 4,


5]
[Link](shallowCopy); // Output: [1, 2, 3, 4,
5]

[Link](originalArray === shallowCopy); // Outpu


t: false

As you can see, the originalArray and shallowCopy are two separate
arrays, and the comparison originalArray === shallowCopy evaluates to

JavaScript 49
false .

1. Concatenating Arrays:

const arr1 = [1, 2, 3];


const arr2 = [4, 5, 6];

// Concatenating arrays using the spread operator


const combinedArray = [...arr1, ...arr2];

[Link](arr1); // Output: [1, 2, 3]


[Link](arr2); // Output: [4, 5, 6]
[Link](combinedArray); // Output: [1, 2, 3, 4,
5, 6]

[Link](arr1 === combinedArray); // Output: false


[Link](arr2 === combinedArray); // Output: false

Here too, the arr1 , arr2 , and combinedArray are separate arrays.

1. Merging Objects:

const person = { name: "John", age: 30 };


const additionalInfo = { job: "Engineer", country: "U
SA" };

// Merging objects using the spread operator


const newPerson = { ...person, ...additionalInfo };

[Link](person); // Output: { name: "John",


age: 30 }
[Link](additionalInfo); // Output: { job: "Engin
eer", country: "USA" }
[Link](newPerson); // Output: { name: "John",
age: 30, job: "Engineer", country: "USA" }

[Link](person === newPerson); // Output: false

JavaScript 50
[Link](additionalInfo === newPerson); // Output:
false

In the case of objects, the spread operator also creates new objects
with separate memory addresses.
In all these examples, the spread operator creates new instances and
does not modify the original arrays or objects. The new instances are
shallow copies or merged versions of the original data. If you need a
deep copy of an object (including nested objects), you would need to
implement custom logic or use libraries that provide deep cloning
functionality.

Concatenating/kənˈkæt(ə)nˌeɪt/ Arrays:

const arr1 = [1, 2, 3];


const arr2 = [4, 5, 6];

// Concatenating arrays using the spread operator


const combinedArray = [...arr1, ...arr2];

[Link](combinedArray); // Output: [1, 2, 3, 4, 5,


6]

Passing Array Elements as Individual Arguments to a Function:

function addNumbers(a, b, c) {
return a + b + c;
}

const numbers = [1, 2, 3];

// Passing array elements as individual arguments using


the spread operator
const sum = addNumbers(...numbers);

JavaScript 51
[Link](sum); // Output: 6

In this example, the spread operator "spreads" the elements of the numbers

array as individual arguments when calling the addNumbers function. So, it's
equivalent to calling addNumbers(1, 2, 3) .

2. Object Spread:

When used with objects, the spread operator creates a shallow copy of the
object or merges multiple objects into a new object. It is essential to note that
the spread operator performs a shallow copy, meaning that nested objects are
still references and not deep-copied.

Example:

const person = { name: "John", age: 30 };


const additionalInfo = { job: "Engineer", country: "USA" };

const newPerson = { ...person, ...additionalInfo };


[Link](newPerson);
// Output: { name: "John", age: 30, job: "Engineer", countr
y: "USA" }

3. Function Arguments:

The spread operator can be used to pass array elements as individual


arguments to a function.
Example:

function addNumbers(a, b, c) {
return a + b + c;
}

const numbers = [1, 2, 3];

JavaScript 52
const sum = addNumbers(...numbers);
[Link](sum); // Output: 6

4. Function Rest Parameters:

Inside a function definition, the spread operator can also be used as a "rest
parameter" to collect multiple function arguments into an array.

Example:

function concatenateStrings(...strings) {
return [Link](" ");
}

const result = concatenateStrings("Hello", "world", "!");


[Link](result); // Output: "Hello world !"

The spread operator provides a concise and expressive way to work with
arrays and objects in JavaScript and is widely used in modern JavaScript
codebases for various tasks, such as array manipulation, object merging, and
function arguments handling.
Callback function
In JavaScript, a callback is a function passed into another function as an
argument to be executed later.

why use it
JavaScript is single-threaded and executes code sequentially, which
means that long-running tasks like making HTTP requests, reading files, or
database queries can block the main thread and make the user interface
unresponsive. By using callback functions, you can control the flow of
execution and ensure that these time-consuming operations happen
asynchronously, without blocking the main thread.

() ⇒ {} / () ⇒ () function
在JavaScript(特别是在ES6及之后的版本)中,箭头函数有两种不同的写法,它们
在语法和返回值上有所不同。让我详细解释一下:

JavaScript 53
1. 带大括号 的箭头函数: {}

当你使用大括号
,箭头函数就不会有隐式返回。也就是说,如果你想返回一个值,你需要显式
{}

地使用 语句。 return

const example = (param) => {


return param * 2;
}

2. 不带大括号的箭头函数:
如果你不使用
,则该函数将隐式返回表达式的结果。这种写法非常适用于简短的函数,因为
{}

它使代码更为简洁。
const example = param => param * 2;

对于你的代码中的例子:
这是一个更完整的函数,可能包含多个语句,并且没
const => {} :
有明确返回值,所以使用 是有意义的。 {}

: 这里使用的是隐式返回,
[Link]((suggestion, index) => ( ... ))

特别是当你希望直接返回JSX时(如在React组件中),这种简洁的写法很有用。
括号 用于包围返回的JSX,确保整个JSX被作为一个整体返回,而不是只返回
()

第一个元素。
希望这能帮助你理解两种写法的差异和用途!
==(loose equality) vs ===(strict equality)
In JavaScript, the operators == (loose equality) and === (strict equality) are
used for comparison between values. Here's an explanation of how they differ:

1. Loose Equality ( == ):

The == operator compares values for equality after performing type


coercion/koʊˈɜːrʒn/ if necessary. It allows for implicit type conversion,
meaning JavaScript will try to convert the operands to a common type
before making the comparison.

JavaScript 54
Example:

5 == '5' // true

In this case, the string '5' is implicitly converted to a number before


comparison, resulting in true .

2. Strict Equality ( === ):

The === operator compares values for equality without performing type
coercion. It checks for both value and type equality . It requires the operands
to have the same type and value to be considered equal.
Example:

5 === '5' // false

In this case, the string '5' and the number 5 have different types, so the
strict equality comparison evaluates to false .

for object :

The general recommendation is to use the strict equality operator ( === ) as it


provides more predictable and reliable results by explicitly checking both the
value and type of the operands. It avoids potential unexpected type coercion
behavior that can occur with loose equality ( == ).

However, there are scenarios where loose equality ( == ) may be used


intentionally, such as when comparing values from different data types where
implicit type conversion is desired.

It's important to note that when comparing objects or complex data types
(arrays, objects), the equality operators ( == and === ) check for reference
equality rather than deep equality. To compare the content of objects or arrays,
you would need to implement custom comparison logic or use libraries/utilities
designed for that purpose.
Function declarations, hoisting

JavaScript 55
is a behavior in JavaScript where function declarations are
Function hoisting

moved to the top of their scope during the compilation phase, allowing them to
be called before they are actually defined in the code.

In JavaScript, you can declare functions using two main syntaxes: function
declarations and function expressions.

1. Function Declarations:
With function declarations, the entire function, including its body, is hoisted
to the top of the current scope.
This means that you can call the function before its actual declaration in
the code.

Example:

greet(); // Output: "Hello"

function greet() {
[Link]("Hello");
}

In the example above, the function greet() is called before its declaration,
and it still works because the function declaration is hoisted to the top of
the scope.

2. ES6 Syntax, Function Expressions:


Function expressions, on the other hand, behave differently in terms of
hoisting.
If you try to call a function expression before its declaration, it will result
in an error
Example:

// var
sayHello(); // Error: sayHello is not defined

var sayHello = function () {


[Link]("Hello");
};

JavaScript 56
// let
sayHello(); // ReferenceError: Cannot access 'sayHello'
before initialization

let sayHello = function () {


[Link]("Hello");
};

In this example, the variable sayHello is hoisted to the top, but since it is
assigned a function expression, the actual function definition is not hoisted.
Hence, trying to call sayHello() before its declaration results in an error.

It's important to note that while function declarations are hoisted, variable
declarations using var , let , or const are also hoisted but with a behavior
called "variable hoisting." However, the assignment of values to variables is not
hoisted. This can lead to unexpected behavior when accessing variables
before they are assigned a value.

To avoid confusion and ensure code readability, it's generally recommended to


declare functions and variables before using them, regardless of hoisting
behavior.
Function: The arguments object
Inside the body of a function, you can access an object called arguments that
represents the named arguments of the function.
The arguments object behaves like an array though it is not an instance of the
Array type.
For example, you can use the square bracket [] to access the arguments:
arguments[0] returns the first argument, arguments[1] returns the second one,
and so on.

function add(para1, para2 ….) {


// return the sum of the arguments
}

DOM manipulation

JavaScript 57
The Document Object Model (DOM) is an application programming interface
(API) for manipulating HTML and XML documents.
The DOM represents a document as a tree of nodes. It provides API that allows
you to add, remove, and modify parts of the document effectively.
In this DOM tree, the
document is the root node. The root node has one child which is the <html>

element. The <html> element is called the document element.

<html>
<head>
<title>JavaScript DOM</title>
</head>
<body>
<p>Hello DOM!</p>
</body>
</html>

Selecting elements
getElementById()
The getElementById() method allows you to retrieve an HTML element from
the document based on its id attribute.

[Link](id);

<!DOCTYPE html>

JavaScript 58
<html>
<head>
<title>Example Page</title>
</head>
<body>
<h1 id="myHeading">Hello, World!</h1>

<script>
const heading = [Link]("myHeading");
[Link] = "Updated Heading";
</script>
</body>
</html>

getElementsByName()

The getElementsByName( ) accepts a name which is the value of the name


attribute of elements and returns a live NodeList of elements.

Note: Although NodeList is not an Array, it is possible to iterate over it with


forEach(). It
can also be converted to a real Array using [Link]().

<input type=”text" name="language" value="JavaScript">


<input type=”text" name="language" value=”Java">
let elements = [Link](”language" );

Live NodeList : A live NodeList is automatically updated


when changes occur in the document structure. If
elements are added, removed, or modified, the live
NodeList reflects those changes.

getElementsByTagName()

getElementsByClassName()

JavaScript 59
If you match elements by multiple classes, you need to use whitespace to
separate them like this:

let btn = [Link]('btn bt-primary’

<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
<style>
.highlight {
background-color: yellow;
}
</style>
</head>
<body>
<p class="highlight">This paragraph will be highlighted.
<p>This paragraph will not be highlighted.</p>
<p class="highlight">This paragraph will also be highlig

<script>
const elements = [Link]("high

for (let i = 0; i < [Link]; i++) {


elements[i].textContent = "Updated Paragraph";
}
</script>
</body>
</html>

The return type: HTMLCollection, which means that any changes made to
the matched elements will be reflected in the collection

querySelector()
The querySelector() is a method of the Element interface. The
querySelector() allows you to find the first element that matches one or

JavaScript 60
more CSS selectors
The querySelector method returns a static NodeList.

let firstHeading = [Link]('h1’); // table


let note = [Link]('.menu-item’); // class
let logo = [Link]('#logo’); // id # -> has ,
querySelectorAll()
querySelectorAll() method to find all elements that match a CSS selector or
a group of CSS selector.

querySelectorAll() returns a static (not live) NodeList representing a list of


the document's elements that match the specified group of selectors

Static NodeList : A static NodeList is a snapshot of the


nodes that matched the given criteria/kraɪˈtɪriə/ at the
time the NodeList was created. It does not update
automatically if changes occur in the document.

!!!querySelector vs querySelectorAll

Manipulating elements
createElement()

To create an HTML element, you use the [Link]()


method

let div = [Link]('div');


[Link] = 'content’;
[Link] = 'note’;
[Link]= Thi s is a Test’;
[Link](div)

appendChild()

JavaScript 61
The appendChild() method allows you to add a node to the end of the list of
child nodes of a specified parent node

[Link](childNode);

function createMenuItem(name) {
let li = [Link]('li’);
[Link] = name;
return li;
}

const menu = [Link]('#menu’);


//dynamic add element to list
[Link](createMenuItem('Home'));
[Link](createMenuItem('Services'));
[Link](createMenuItem('About Us'));

append()
The [Link]() method inserts a set of Node objects or
DOMString objects after the last child of a parent node:

[Link](...nodes);

<ul id="app">
<li>JavaScript</li>
</ul>

let app = [Link]('#app');


let langs = ['TypeScript', 'HTML', 'CSS'];
let nodes = [Link](lang => {
let li = [Link]('li');
[Link] = lang;
return li;
});
[Link](...nodes);

JavaScript 62
Then:
<ul id="app">
<li>JavaScript</li>
<li>TypeScript</li>
<li>HTML</li>
<li>CSS</li>
</ul>

As you can see, the additional list items for the languages 'TypeScript',
'HTML', and 'CSS' are dynamically added to the existing unordered list.
The append() method has no return value.
It means that the append() method implicitly returns undefined.

!!!append() vs appendChild()

Return value: .append does not have a return value


while .appendChild returns the appended Node object

Input: .append allows you to add multiple Node Objects(but each item
needs to be provided as a separate argument. The items are appended
one by one in the order they are specified.) while appendChild allows
only a single Node Object

Parameter Types: .append accepts Node objects and DOMStrings


while .appendChild accepts only Node objects

textContent()

To get or set the text content of a node and its descendants, you use the
textContent property

<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<div id="note">

JavaScript 63
JavaScript textContent Demo!
<span style="display:none">Hidden Text!</span>
<!-- my comment -->
</div>

<script>
let note = [Link]('note');
[Link]([Link]);
</script>
</body>
</html>

Output:
JavaScript textContent Demo!
Hidden Text!

When you set the textContent property on a node, all the node's children are
removed, and a single text node containing the new text value replaces
them.

<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<div id="message">
<p>This is the initial message.</p>
<span>Additional text.</span>
</div>

<script>
let message = [Link]('message');
[Link] = 'Updated message';
</script>
</body>

JavaScript 64
</html>

Then:
<div id="message">
Updated message
</div>

innerHTML()
The innerHTML allows you to get or set the HTML content within an element.
It provides a way to access or modify the markup, including tags,
attributes, and text, of an element and its descendants.

<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<div id="content">
<p>This is the initial content.</p>
<span>Additional text.</span>
</div>

<script>
let content = [Link]('content');
[Link]([Link]);
// Output: <p>This is the initial content.</p><spa

[Link] = '<h2>Updated content</h2><p>New pa


</script>
</body>
</html>

Then:
<div id="content">

JavaScript 65
<h2>Updated content</h2>
<p>New paragraph</p>
</div>

Security vulnerabilities: If you dynamically insert user-generated or


untrusted content into the innerHTML property, there is a risk of introducing
security vulnerabilities such as cross-site scripting (XSS) attacks.

!!!innerHTML() vs textContent()

1. Both of them allow you to get or set the HTML content within an
element.

2. innerHTML: When accessed, it returns a string representing the HTML


markup inside the element, including the element's own tags, child
elements, and text. textContent: When accessed, it returns a string
representing the concatenated/kənˈkæt(ə)nˌeɪtid/ text content of the
element and its descendants/dɪˈsendənts/, excluding any HTML tags or
attributes.

3. the innerHTML : property allows you to convert a string into HTML tags.
When set, it replaces the entire content of the element with the
specified HTML markup. textContent: When set, it replaces all child
nodes of the element with a single text node containing the specified
text.

insertBefore()
To insert a node before another node as a child node of a parent node, you
use
the parentNode.
insertBefore()

[Link](newNode, existingNode);

• The newNode is the new node to be inserted.


• The existingNode is the node before which the new node is inserted. If
the existingNode is null, the insertBefore() inserts the newNode at the end
of the parentNode‘s child nodes

JavaScript 66
function insertAfter(newNode, existingNode){
[Link](newNode, existing
}

prepend()
The prepend() method inserts a set of Node objects or DOMString objects
after the first child of a parent node:

[Link](...nodes); // need to insert one by one


[Link](...DOMStrings);

By using the spread operator ”…”, we can pass the elements of the nodes

array as separate arguments to the prepend() method.

replaceChild()

<ul id="menu">
<li>Homepage</li>
<li>Services</li>
<li>About</li>
<li>Contact</li>
</ul>
let menu = [Link]('menu');
// create a new node
let li = [Link]('li');
[Link] = 'Home';
// replace the first list item
[Link](li, [Link]);

removeChild()

To remove a child element of a node, you use the removeChild() method

let childNode = [Link](childNode);

JavaScript 67
The childNode is the child node of the parentNode that you want to
remove.
If the childNode is not the child node of the parentNode, the method throws
an exception.
The removeChild() returns the removed child node from the DOM tree but
keeps it in the memory, which can be used later.
You can directly use: [Link](childNode);

How to remove all child nodes of an element ?

let menu = [Link]('menu');


while ([Link]) {
[Link]([Link]);
}

Working with Events - Ways to create event


1. HTML Event Handler Attributes: You can use HTML event handler attributes
directly within HTML tags to define event handlers. For example, onclick ,
onmouseover , onkeydown , etc.

<button me</button>

<script>
function handleButtonClick() {
[Link]('Button clicked!');
// Additional code logic here...
}
</script>

Assigning event handlers using HTML event handler


attributes are considered as bad practices, reasons:
First, the event handler code is mixed with the HTML
code, which will make the code more difficult to maintain
and extend.

JavaScript 68
Second, it is a timing issue. If the element is loaded fully
before the JavaScript code, users can start interacting
with the element on the webpage which will cause an
error.
2. DOM Level 0 Event Handlers: You can assign a function directly to a
specific event property of a DOM element. For example:

const button = [Link]('button');


[Link] = function() {
[Link]('Button clicked!');
};

To remove the event handler, you set the value of the event handler
property to null:

[Link] = null;

3. DOM Level 2 Event Listeners:


DOM Level 2 Event Handlers provide two main methods for dealing with the
registering/deregistering event listeners:

addEventListener() – register an event handler

removeEventListener() – remove an event handler

It allows you to attach multiple event listeners to an element for a specific


event type. For example

const button = [Link]('button');


[Link]('click', function() {
[Link]('Button clicked!');
});

JavaScript 69
FYI: You need to pass the same arguments as were passed to the
addEventListener(), using an anonymous event listener will not work.
Events Flow - Events Bubbling(default)
In the event bubbling model, an event starts at the most specific element and
then flows upward toward the least/liːst/ specific element.

When you click the button/ˈbʌt(ə)n/, the click event occurs in the following
order:

1. button

2. div with the id container

3. body

4. html

5. document

Events Flow - Event capturing


In the event capturing model, an event starts at the least/liːst/ specific element
and flows

downward toward the most specific element.


When you click the button
/ˈbʌt(ə)n/, the click event occurs in the following order:

1. document

JavaScript 70
2. html

3. body

4. div with the id container

5. button

Event Object - Properties and Methods


When the event occurs, the web browser passed an Event object to the event
handler:

let btn = [Link]('#btn');

[Link]('click', function(event) {
[Link]([Link]);
});

Event object properties and methods firing / ˈfaɪərɪŋ /

JavaScript 71
!!!preventDefault() vs stopPropagation()

preventDefault()
To prevent the default behavior of an event, you use the preventDefault()
method.
For example, when you click a link, the browser navigates you to the URL
specified in the href attribute (hypertext reference), if you don't want this to
happen, you can use
preventDefault() to stop it.

<a href=”[Link] End Training

let link = [Link]('a');

[Link]('click',function(event) {
[Link]('clicked');
[Link]();
})

stopPropagation()
The stopPropagation() method immediately stops the flow of an event
through the DOM tree. However, it does not stop the browers default
behavior.

JavaScript 72
For example, if you have a click event on an <a> link element and you call
stopPropagation() within the event handler, the event will not bubble to any

parent elements, but the link will still be followed (the default behavior of a
click event on an anchor link).
If you want to prevent the default behavior, you'd need to use the
preventDefault() method:

[Link]('click', function(event) {
[Link]();
[Link]();
});

By calling preventDefault() , you'll prevent the browser from following the


link.

let btn = [Link]('#btn');

[Link]('click', function(event) {
[Link]('The button was clicked!');
[Link](); // add later
});

[Link]('click',function(event) {
[Link]('The body was clicked!');
});

Event Delegation
With event delegation/ˌdelɪˈɡeɪʃn/, you attach a single event listener to a
parent element and handle events that occur on its child elements by utilizing
event bubbling. This is useful when you have dynamic or large numbers of
elements.

const parent = [Link]('parent');


[Link]('click', function(event) {
if ([Link] === 'BUTTON') {

JavaScript 73
[Link]('Button clicked!');
}
});

Why Event Delegation?

To handle the click event of each menu item, you may add the corresponding
click event handlers: not good

<ul id="menu">
<li><a id="home">home</a></li>
<li><a id="dashboard">Dashboard</a></li>
<li><a id="report">report</a></li>
</ul>

let home = [Link]('#home');

[Link]('home',(event) => {
[Link]('Home menu item was clicked');
});

let dashboard and let report…….(same logic as the code above)

In JavaScript, if you have a large number of event handlers(more than 200) on


a page, these event handlers will directly impact the performance because of
the following reasons:

First, each event handler is a function which is also an object


that takes up memory . The more objects in the memory, the
slower the performance.
Second, it
takes time to assign all the event handlers , which causes a
delay in the interactivity of the page.

Event Delegation(take the advantage of event bubbling ) can help.

JavaScript 74
Instead of having multiple event handlers, you can assign a single event
handler to handle all the click events:

<ul id="menu">
<li><a id="home">home</a></li>
<li><a id="dashboard">Dashboard</a></li>
<li><a id="report">report</a></li>
</ul>

let menu = [Link]('#menu');


[Link]('click', (event) => {
let target = [Link];
switch ([Link]) {
case 'home':
[Link]('Home menu item was clicked');
// Additional code logic for handling the click event o
break;
case 'dashboard':
[Link]('Dashboard menu item was clicked');
// Additional code logic for handling the click event o
break;
case 'report':
[Link]('Report menu item was clicked');
// Additional code logic for handling the click event o
break;
}
});

JavaScript Advanced Topic - Anonymous Functions


An anonymous/əˈnɑːnɪməs/ function is a function without a name. An
anonymous function is often not accessible after its initial creation.

let show = function () {


[Link]('Anonymous function');
};

JavaScript 75
// ES6
let show = () => {
[Link]('Anonymous function');
};

show();

In this example, the anonymous function has no name between the function
keyword and parentheses ().

We often use anonymous functions as arguments of other functions. For


example:
Callback function.
JavaScript Advanced Topic - immediately invoked function
IIFE /ˈɪfi/
A JavaScript immediately invoked function expression(IIFE) is a function
defined as an expression and executed immediately after creation.
Once the IIFE has completed its execution, the variables and functions within
its scope are destroyed, and it cannot be directly executed again.

How about giving a name to IIFE ? it cannot be invoked again after execution.
In essence, an IIFE is a design pattern that allows you to define an anonymous
function, invoke it immediately, and not pollute the global namespace. It's
commonly used in JavaScript to create module-like structures within code.

How to define one

1. Start with a Function Expression: At the core, an IIFE begins as a


regular function expression.

function() {
// function code here
}

JavaScript 76
2. Enclose the Function Expression in Parentheses/pəˈrenθəsiːz/: The
function is enclosed within an outer set of parentheses. This is done to
distinguish the function as an expression, not a declaration. By
wrapping our anonymous function inside parentheses, we're telling the
JavaScript parser to treat it as an expression.

(function() {
// function code here
})

3. Invoke the Function: To immediately invoke the function expression,


you add another set of parentheses/pəˈrenθəsiːz/ at the end.

(function() {
// function code here
})()

4. Passing Arguments: If you want to pass arguments to your IIFE, you


can place them inside the outer set of parentheses.

(function(a, b) {
[Link](a + b);
})(1, 2) // This will log 3 to the console

5. Using Arrow Functions: An IIFE can also be defined using arrow


functions.

(() => {
// function code here
})()

6. Return Values: Just like any other function, an IIFE can return a value
which can be assigned to a variable.

JavaScript 77
let result = (function(a, b) {
return a + b;
})(2, 3) // result will be 5

Why use IIFE?

1. Avoid global scope pollution: By wrapping code inside an IIFE, you


avoid adding many variables and functions to the global scope. This
helps prevent naming collisions and keeps your code modular.

2. Data privacy: Any variables or functions defined inside the IIFE cannot
be accessed from the outside, providing a level of data privacy.

3. Immediate execution: Sometimes, you just want a piece of code to


execute immediately without leaving any trace (like function
declarations) behind.

(function() {
[Link]('IIFE executed!');
})();

// ES6 syntax:
(() => {
[Link]('IIFE executed!');
})();

Closure ppt105 -108


In JavaScript, a closure is created when a function is defined inside another
function and the inner function has access to the variables and parameters of
the outer function, even after the outer function has returned. This allows the
inner function to "remember" the values of those variables and parameters,
even if they are no longer in scope.

A closure is the combination of a function bundled/ˈbʌndld/ together


(enclosed) with references to its surrounding state (the lexical environment).
In other words, a closure gives you access to an outer function's scope from
an inner function. It allows the function to retain access to variables,

JavaScript 78
parameters, and other functions within its outer (enclosing) scope even after
the outer function has finished executing.

function outerFunction() {
var outerVariable = 'Hello';

function innerFunction() {
[Link](outerVariable);
}

return innerFunction;
}

var closure = outerFunction();


closure(); // Output: Hello

In this example, outerFunction is defined, which declares an outerVariable and an


innerFunction within its scope. The innerFunction has access to the outerVariable

due to closure. When outerFunction is called and assigned to the variable


closure , it returns the innerFunction . Then, closure() is called, and it still has

access to the outerVariable even though outerFunction has finished executing.


The value 'Hello' is logged to the console.

Why use Closure?

Data Privacy: Closures allow you to create private variables and functions
that are inaccessible from outside the scope of the outer function. This
helps in encapsulating/ɪnˈkæpsjuleɪtɪŋ/ data and preventing unwanted
access or modification.
Closure + asynchronous

for (var index = 1; index <= 3; index++) {


setTimeout(function () {
[Link]('after ' + index + ' second(s):' + index)
}, index * 1000);
}

JavaScript 79
Output:
after 4 second(s):4
after 4 second(s):4
after 4 second(s):4

Why It happened ?

1. Use var to declare variable(non block scope) will be considered as a global


variable

2. It is an asynchronous task(setTimeout), the asynchronous tasks will be put


into the
task queue.

3. When the synchronous tasks are completed, the asynchronous tasks will
be executed(setTimeout)

How to fix it ?

Using the IIFE solution: an IIFE creates a new scope by declaring a function
and immediately execute it.

for (var index = 1; index <= 3; index++) {


(function (index) {
setTimeout(function () {
[Link]('after ' + index + ' second(s):' +
}, index * 1000);
})(index);
}

Using let keyword in ES6:


It will create a new lexical/ˈleksɪk(ə)l/ scope in each iteration. In other
words, you will have a new index variable in each iteration.

By using let to declare the index variable, it creates a new block scope for
each iteration of the loop. Each callback function captures its own separate
value of index , which remains unchanged during its execution.

JavaScript 80
for (let index = 1; index <= 3; index++) {
setTimeout(function () {
[Link]('after ' + index + ' second(s):' + ind
}, index * 1000);
}

Currying Function
Currying is a technique in functional programming where a function with
multiple arguments is transformed into a sequence of functions, each taking a
single argument. The curried functions can be called with one argument at a
time, and each call returns a new function that expects the next argument until
all arguments have been provided, and the final result is returned.
Here's an example of a curried function in JavaScript:

function add(x) {
return function(y) {
return x + y;
};
}

// Curried function usage


var increment = add(1); // Returns a function that incremen
ts by 1
[Link](increment(5)); // Output: 6

var addTen = add(10); // Returns a function that adds 10


[Link](addTen(5)); // Output: 15

// ES6
const add = x => y => x + y;

// Curried function usage


const increment = add(1); // Returns a function that increm
ents by 1

JavaScript 81
[Link](increment(5)); // Output: 6

const addTen = add(10); // Returns a function that adds 10


[Link](addTen(5)); // Output: 15

The add() function behaves like a function factory. It creates increment() and
addTen() functions with the respective x parameter 1 and 10.
The increment() and addTen() are closures. They share the same function
body but store different scopes.

In this example, the add function takes one argument ( x ) and returns another
function that takes a second argument ( y ). The returned function adds the
values of x and y and returns the result. By calling add with one argument, we
get a partially applied function that we can reuse with different arguments.

Currying is useful in scenarios where you want to create reusable functions


with partially applied arguments or when you want to build more specific
functions from more general functions.
JavaScript Advanced Topic - Passing by value(primitive data
types)
When primitive data types (such as numbers, strings, booleans) are passed as
function arguments or assigned to another variable, they are passed by value .
This means that a copy of the value is made and assigned to the new variable
or passed to the function. Modifying the copy does not affect the original
value.

let x = 10;

function modifyValue(a) {
a = 20;
[Link](a); // Output: 20
}

modifyValue(x);
[Link](x); // Output: 10

JavaScript 82
In this example, the value of x is copied and assigned to the variable a inside
the modifyValue function. Modifying a does not affect the value of x outside
the function.
JavaScript Advanced Topic - Passing by value of
object(objects)
When objects (including arrays and functions) are assigned to variables or passed
as function arguments, they are passed by reference . This means that instead of
creating a new copy of the object, a reference to the same object in memory is
passed or assigned. Modifying the object through the reference will affect the
original object.

let obj = { value: 10 };

function modifyObject(o) {
[Link] = 20;
[Link]([Link]); // Output: 20
}

modifyObject(obj);
[Link]([Link]); // Output: 20

In this example, obj is an object, and when it is passed to the modifyObject

function, the reference to the object is passed. Modifying the o variable inside
the function also modifies the obj object.

call(), apply() and bind()


call() vs apply() vs bind()
Same : All three of these JavaScript methods allow you to change the value
of this for a given function.
difference :

Call() invokes the function and allows you to pass in arguments one by
one.

Apply() invokes the function and allows you to pass in arguments as an


array.

JavaScript 83
Bind() returns a new function, then you can execute this function by
passing the arguments.

1. call() : The call() method is used to invoke a function with a specified


this value and arguments provided individually. It takes the this value as
the first argument, followed by the function arguments separated by
commas.

The first argument of the call() method thisArg is the this


value. It allows you to set the this value to any given
object. By default, the this value inside the function is set
to the global object i.e., window on web browsers and
global on [Link]. Note that in the strict mode,
the this inside the function is set to undefined instead of
the global object.

[Link](thisArg, arg1, arg2, ...);

2. apply() : The [Link]() method allows you to call a


function with a given this value and arguments provided as an array.

[Link](thisArg, [args]);

The apply() method accepts two arguments:


The
thisArg is the value of this provided for the call to the function fn.
The
args argument is an array that specifies the arguments of the function fn.
Since the ES5, the args argument can be an array-like object or array
object.
The apply() method is similar to the call() method except that
it takes the arguments of the function as an array instead of the
individual arguments.

JavaScript 84
const person = {
firstName: 'John',
lastName: 'Doe'
};

function greet(greeting, message) {


return `${greeting} ${[Link]}. ${message}`;
}

greet('Hi', 'How are you');


// Output: "Hi undefined. How are you"

[Link](person, ['Hi', 'How are you']);


// Output: "Hi John. How are you"

When you invoke greet('Hi', 'How are you') , the function is called directly
without specifying a context ( this value). In this case, the this value
inside the greet function is undefined , as there is no specific object or
context assigned.
However, when you use apply() to invoke the function with a specific
context ( person ) and pass the arguments as an array, like [Link](person,
['Hi', 'How are you']) , the this value inside the greet function is set to the

person object. The arguments 'Hi' and 'How are you' are passed as
separate elements of the array.

3. bind() : The bind() method is used to create a new function with a bound
this value. It does not immediately invoke the function but returns a new
function with the specified this value permanently bound. It allows you to
curry or preset arguments for the function.

在JavaScript中, 方法用于创建一个新的函数,其中新函数的 值被指


bind() this

定为传递给 的第一个参数,同时也可以指定绑定函数的一部分参数。这样
bind()

做的目的是为了将函数与特定的对象绑定在一起,以便在后续调用中确保函数中
的 值始终指向指定的对象。
this

的基本用法如下:
bind()

JavaScript 85
const boundFunction = [Link](thisArg, arg
1, arg2, ...);

要绑定的原始函数。
originalFunction :

: 指定绑定函数中的
thisArg 值,即函数执行时的上下文对象。
this

,
arg1 , ...: 可选参数,用于绑定函数的部分参数(也称为偏函数),在
arg2

调用绑定函数时,这些参数会被插入到原始函数的参数之前。
下面是一个使用 的简单示例:
bind()

const person = {
name: 'John',
sayHello: function() {
[Link](`Hello, my name is ${[Link]}.`);
}
};

const otherPerson = {
name: 'Alice'
};

const sayHelloToOtherPerson = [Link](other


Person);

[Link](); // Output: "Hello, my name i


s John."
sayHelloToOtherPerson(); // Output: "Hello, my name i
s Alice."

在上面的示例中,我们有一个 对象,其中包含 person sayHello 方法。我们使用


方法创建了一个新函数
bind() ,将 sayHelloToOtherPerson person 对象的 方
sayHello

法绑定到 对象上。因此,在调用
otherPerson sayHelloToOtherPerson()时,该函数中
的 值将指向
this 对象,而不是 对象。
otherPerson person

JavaScript 86
方法通常用于创建具有固定上下文的回调函数,避免 值在调用时丢失
bind() this

或指向错误的对象。它在React组件中经常用于事件处理程序,确保事件处理程序
函数中的 值始终指向组件实例。
this

Promise
In JavaScript, a promise is an object that returns a value which you hope to
receive in the future, but not now.
Because the value will be returned by the promise in the future, the promise is
very wellsuited for handling asynchronous operations.
A promise has three states:
• Pending: you don’t know if you will complete learning JavaScript by the next
month.
• Fulfilled: you complete learning JavaScript by the next month.
• Rejected: you don’t learn JavaScript at all

Async and await


An async function is a function declared with the async keyword, and the await
keyword is permitted within them. The async and await keywords enable
asynchronous, promise-based
behavior to be written in a cleaner style, avoiding the need to explicitly
configure promise chains.
Async and await should be used in together.

Event Loop
The event loop is a constantly running process that monitors both the callback
queue and the call stack.

When dealing with JavaScript, the runtime uses an event loop to handle
synchronous and asynchronous operations, allowing it to perform non-blocking
I/O operations despite being single-threaded.

For Synchronous Operations: These operations are added to the call stack and
are executed one by one, in the order they were added (this is known as LIFO -
Last In, First Out). Each function waits for the previous function to complete. If
a function is taking too long to run (like a large loop or complex computation), it
can cause the webpage to become unresponsive until that function is done.
This is because the call stack needs to be cleared before anything else (like
user interactions, rendering updates, etc.) can happen.

JavaScript 87
For Asynchronous Operations: Unlike synchronous operations, asynchronous
operations do not block the call stack. When an async operation is initiated
(like making a fetch request, setting a timer, etc.), it's handled off to a web API
provided by the browser. This lets the call stack clear and continue running
other tasks.
The web API manages the operation in the background, separate from the main
JavaScript thread. Once the async operation is complete (like when the fetch
request receives a response, or the timer finishes), the web API adds a
callback function to the task queue.

The event loop constantly checks if the call stack is empty. When the call
stack is clear (meaning all synchronous tasks have completed), the event loop
takes the first task from the task queue and pushes it to the call stack, allowing
the callback function to run.

Event loop allows JavaScript to handle both synchronous and asynchronous


operations in an efficient way. Even though JavaScript is single-threaded, this
model lets it perform non-blocking operations, making it suitable for tasks like
handling user interactions, making network requests, and more.

(block function): A function that takes a long time to complete is called a


blocking function. It blocks all the interactions on the webpage, such as
mouse click.

An example is a function that calls an API from a remote server.

To prevent a blocking function from blocking other activities, you


typically put it in a callback function for execution later. (eg:
setTimeout())

JavaScript 88
[Link]

If the call stack is not empty, the event loop waits until it is empty and places
the next function from the callback queue to the call stack. If the callback
queue is empty, nothing will happen.

Here's a simplified explanation of how the event loop works:

1. Call Stack: The JavaScript runtime maintains a call stack, which is a data
structure that keeps track of the functions being executed. When a function
is called, it is added to the top of the call stack, and when a function
completes, it is removed from the stack.

JavaScript 89
2. Event Queue: In addition to the call stack, there is an event queue that
holds events or tasks to be processed. Events can include user
interactions, network requests, timers, and more.

3. Event Loop: The event loop continuously monitors the call stack and the
event queue. It performs the following steps:

If the call stack is empty, it checks the event queue for pending events.

If there are events in the queue, it takes the first event and pushes its
corresponding callback function onto the call stack for execution.

The function execution begins, and any synchronous code inside the
function is executed.

If there are asynchronous operations (e.g., setTimeout, AJAX requests),


they are handed off to the browser or runtime environment for
execution, and the function completes.

The event loop repeats this process, checking the call stack and event
queue, and continues to process events as they become available.

By following this cycle, the event loop ensures that JavaScript can handle
asynchronous operations without blocking the main thread, allowing for a
responsive user interface and efficient resource utilization.
It's important to note that callbacks or promises associated with asynchronous
operations are not executed immediately when they are defined. Instead, they
are placed in the event queue and executed by the event loop when the call
stack is empty.

What if you explain the event loop in the sync and async operationally ?
this
In JavaScript, you can use the this keyword in the global and function contexts.
Moreover, the behavior of the this keyword changes between strict and
nonstrict modes.

What is the this keyword?

The this references the object of which the function is a property. In other
words,
the this references the object that is currently calling the function.

JavaScript 90
Global context
In the global context, the this references the global object, which is the
window object on the web browser or global object on [Link].

JavaScript 91

You might also like