[Go to site: main page, start]

0% found this document useful (0 votes)
51 views179 pages

JavaScript Programming Concepts Guide

The document provides a comprehensive overview of JavaScript programming, covering key concepts such as procedural and object-oriented programming, data types, variables, operators, conditionals, loops, functions, scope, objects, arrays, error handling, and JSON. It also discusses ECMAScript versions, the importance of namespaces, and various programming patterns. Additionally, it addresses common issues like floating-point precision and type conversion in JavaScript.

Uploaded by

杜韦萱
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)
51 views179 pages

JavaScript Programming Concepts Guide

The document provides a comprehensive overview of JavaScript programming, covering key concepts such as procedural and object-oriented programming, data types, variables, operators, conditionals, loops, functions, scope, objects, arrays, error handling, and JSON. It also discusses ECMAScript versions, the importance of namespaces, and various programming patterns. Additionally, it addresses common issues like floating-point precision and type conversion in JavaScript.

Uploaded by

杜韦萱
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

Programming Type
Procedural Programming
Object Oriented Programming
Variables
Namespace
Data Types
Primitive Data Type/ Value
Floating Point Precision Issue
Reference Data Type/ Value
Reference Type: Array
Reference Type: Object
typeof()
Type Conversion @ Typecasting
Explicit Type Conversion
Implicit Type Conversion
Strict Equality (=== & !==)
Examples and Peculiarities
Summary
Operators
Arithmetic Operators
Comparison Operators
Comparison of Strings
Comparison of Numbers
Comparison of undefined
Logical Operators
Comma Operators
Conditional (ternary) operator
Exercise
Conditionals
If statement
Switch statement
Loops
for loop
while loop
do while loop
Function
Why do we need function?
Function Definition
Function Declaration
Function Expression - usually refers to anonymous fn
Immediately Invoked Function Expression (IIFE)
IIFE Deep Dive
Parameters & Arguments
Mapping Case
Return
Recursion
Callee & Caller
Scope
JavaScript Engine Overview
Precompilation (Memory Creation Phase)
Implied globals?
Precompilation in Function Scope
Precompilation in Global Scope
Scope & Scope Chain
[[Scope]]
Execution Context
Scope Chain
Variable Objects
Activation Objects
Closure
Objects
Accessing Object Properties
Create, Read, Update, Delete (CRUD) of Property
Ways to Create Objects
Internal Mechanism of a Constructor Function
Wrapper Classes
Prototype (Ancestor of Objects)
Create, Read, Update, Delete in Prototype
What's inside prototype?
Check constructor
Check prototype
Prototype Chain
CRUD
Does every object have prototype?
[Link]
Call & Apply
Call
Apply
Exercise
Inheritance
History of Inheritance
Method Chaining
Object Enumeration (for...in loop)
Differentiate Object and Array
This
Exercise
Clone
Shadow Copy
Deep Copy
Array
Definition
Read and Write of Array
Array method (ES3.0)
Change original array
No change original array
Array-like Object
Try...Catch
Error Name
Use Strict (ES5.0)
Date Object
Scheduling a Call
Javascript Object Notation (JSON)
XML
JSON
Convert JSON
1. [Link](obj)

2. [Link](str)

Revision
Wrapper
Prototype
This and Call
call / apply and borrowing
Closure
new and constructor function
Private Variable/ property
Deep Copy
Exercise
Frontend
blog
JavaScript Design Patterns

Javascript
ECMAScript
DOM - control html
BOM - control browser

ECMAscript
1.0 - abandoned
2.0 - no use
3.0 - standard, basic
5.0 - might have compatibility between old and new browser
6.0 - latest, newest
7.0

Note:

1. DOM & BOM might behave differently in different browser.


2. Compatibility issues comes from DOM and BOM.
3. BOM is less use in developement.

Programming Type

Procedural Programming
step by step like computer thinking
previous code we wrote.
c,JavaScript (half)
Object Oriented Programming
Java, JavaScript (half)

Variables
Concept:

1. Scoping
2. variable assignment vs mutation
3. hoisting
4. reference
5. copy and clone
6. heap and stack

Declare/ create variable using the following keyword:

var: declares function-scoped or globally-scoped variables, old-school.

let: declare re-assignable, block-scoped local variable, modern.

var & let initialization of value is optional.

// declare variable.
let name;
name = 'wx';

// declare + initialize (assign value)


let city = 'Muar';

const: declares block-scoped local variables in which the value is a constant and reassignment is not
allowed.

must initialize with value during declaration.


declare Object with const, its reference can't be reassigned, its properties is mutable.

// CONSTANT must initialize with value.


const PI = 3.14;

use camelCase to name variables.


Capital-named constants are only used as aliases for 'hard-coded' values.

const COLOR_RED = "#F00";


const COLOR_GREEN = "#0F0";
const COLOR_BLUE = "#00F";
const COLOR_ORANGE = "#FF7F00";

let color = COLOR_ORANGE;

Temporal dead zone (TDZ) is the area of a block where a variable is inaccessible until the
moment the computer completely initializes it with a value.

Namespace
manage variables, prevent Namespace pollution.

suitable for Modular programming - a concept where developers separate program functions into
independent pieces.

Common issues when multiple developers work on different pieces and combine their works, there's a
high chance of getting name conflict.

Example:
<head>
<script src="[Link]"></script>
<script src="[Link]"></script>
<script src="[Link]"></script>
</head>

Solution for Namespace Pollution:

1. Namespacing - with object

var org = {
department1: {jicheng : {
name: 'abc',
age: 123,
}, xuming : {}},
department2: {zhangsan : {}, lisi : {}},
}

[Link]([Link]);

var jicheng = [Link];

2. Closure - with function


var name = 'bcd';
var init = (function () {
var name = 'abc';

function callName() {
[Link](name);
}
return function () {
callName();
}
}())

var initDeng = (function () {


var name = 123;
function callName() {
[Link](name);
}
return function () {
callName();
}
}())

init(); // abc
initDeng(); // 123

Data Types
Js: dynamic and weak typed language。

dynamic: variable is not directly associated with any particular value type.

let foo = 42; // number


foo = 'bar'; // string
foo = true; // boolean

weakly typed: allow implicit type conversion when an operation involves mismatched types, instead of
throwing type errors.
const foo = 42;
const result = foo + '1';
[Link](result); // 421

When a property is accessed on a primitive value, JavaScript automatically wraps the value into the
corresponding wrapper object and accesses the property on the object instead.

Primitive Data Type/ Value


Primitive values are immutable (can't be modified after creation)

let str = 'abc';


str[1] = '2';
[Link](str); // 'abc'

Compared by values.

const a = 1;
const b = 1;
[Link](a === b); // true

undefined: represents the absence of a value

variable declaration without initialization (let x;)


functions/ methods return undefined if no value is returned (return;)
access non-existent object property (obj.x)
type: undefined

null : represents the intentional absence of any object value/ object.

type: object (due to historical bug)

// foo is known to exist now but it has no type or value:


const foo = null;
foo; //nul

String: represents a sequence of characters that represents text.

Number: represents the double-precision floating point IEEE 754-2019 binary64 values.

integer
float
NaN (Not a Number):
Number(undefined) -> NaN
Number('123a') -> NaN (failure to parse string containing letter)
Infinity/ -Infinity

Boolean: represents a logical entity having two values, called true and false.

undefined !== null // true

Floating Point Precision Issue


avoid doing math with decimal numbers.

Safe Boundary for calculation:


whole number: 16 places and below
decimal number: 16 places and below

Note: The imprecision still exist when calculating using decimal number regardless of its safe
boundary for calculation.
// Decimal precision
[Link](0.1 + 0.2); //0.30000000000000004

[Link](0.14 * 100); // 14.000000000000002

// Rounding Introduction- one of the ways to solve.


[Link]([Link](123.234)); // 124
[Link]([Link](123.9999)); // 123

// Random Number Introduction


[Link]([Link]()); // random number x where 0 <= x < 1

// Example 1 - toFixed has precision problem due to Js bug.


for (var i = 0; i < 10; i ++) {
var num = [Link]().toFixed(2) * 100;
[Link](num);
}
/*
46
13
31
71
13
85
63
57.99999999999999 *precision issue
67
44
*/

// Example 2 - round first - no precision problem **

for(var i = 0; i < 10; i ++) {


var num = [Link]([Link]()*100);
[Link](num);
}
/*
52
31
61
88
24
40
59
69
32
71
*/

// Example 3 - Scientific Notation when decimal places >= 7


0.0000001 + 0.0000001 // 2e-7
0.000001 + 0.000001 // 0.000002

// Example 4 - whole number before decimal point

// 16 places and below - good


[Link](1000000000000001 + 1000000000000001); // 2000000000000002
// 17 places and above - imprecision
[Link](10000000000000001 + 10000000000000001); // 20000000000000000

// Example 5 - decimal number after decimal point

// 16 places and below - good


[Link](0.1000000000000001 + 0.1000000000000001); //0.2000000000000002

// 17 places and above - imprecision


[Link](0.10000000000000001 + 0.10000000000000001); // 0.2

Reference Data Type/ Value


Non-primitive values/ Reference values are mutable (can be modified even after creation).
compared by reference.

const arr1 = [1,2]; // memory location reference 1


const arr2 = [1,2]; // memory location reference 2

[Link](arr1 === arr2); // false:arr1 and arr2 store reference to their memory location, not

Object: a collection of properties (“key: value” pair). Each property is either a data property, or an
accessor property. Nearly all objects in JavaScript are instances of Object:
Object

const obj = {
a = 1,
n = 2,
}

Array

const arr = [1, 'a', true];

function

function sum (a, b) {


return a + b;
}

Reference Type: Array


storing a collection of multiple items under a single variable name, and has members for performing
common array operations
let arr = [1, 2, 3, "a", undefined, true, [1, 2, 3]];

// read
[Link](arr[0]);

// write
arr[1] = 'changed';

// check length of an array


[Link]([Link]);

// enumerate an array

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


[Link](arr[i]);
arr[i] = 1;
}

let arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

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


arr2[i] += 1;
}

Reference Type: Object


store various keyed collections and more complex entities.

key & value pair

key is used to get value.


let obj = {
lastName: "Deng",
age: 40,
sex: undefined,
wife: "xiaoliu",
isHandsome: true,

// read
[Link]([Link]);

// write
[Link] = 41;

typeof()
returns a string indicating the type of the operand's value.

Note: [Link](a) where a is not declared will raise reference error. using typeof(a) will not raise
error.

six data type:

1. number
2. string
3. boolean
4. undefined
5. object
6. function

two way of writing it:

1. typeof(xxx)

[Link](typeof(123)); // number

2. typeof xxx
[Link](typeof '123'); //string
[Link](typeof 1); //number
[Link](typeof 1.5); // number
[Link](typeof true); // boolean
[Link](typeof undefined); // undefined
[Link](typeof null); // object - previously used for empty object, represent an empty objec
[Link](typeof {a: 'a', b: 'c'}); // object
[Link](typeof [1, 2, 3, 4, 5]); // object
[Link](typeof function(){return "a"}); // function

// return value of typeof


// note a is not even declared - and no error.
[Link](typeof a); // undefined - a is undefined type
[Link](typeof(typeof(a))); // but typeof(a) returns a string of "undefined"

// see, it is clearly a string


let a = 1 + typeof(z);
[Link](a); // 1undefined

// Example 11
typeof null; // 'object' - special case due to historical bug.
typeof {}; // 'object'
typeof []; // 'object'
typeof ''; // 'string'

Type Conversion @ Typecasting


transfer of data from one data type to another.

// JavaScript is different than other programming language


// operation involves typecasting
// note: - * / => string convert to number

let num = "2" - "1";


[Link](typeof(num) + " " + num); // number 1

let num = 1 * "1";


[Link](typeof(num) + " " + num);
Explicit Type Conversion
1. Number(mix)

let num = Number('123'); // convert string to number and return the value
[Link](typeof(num) + " : " + num); //number : 123

[Link](Number(true)); // 1
[Link](Number(false)); //0
[Link](Number(null)); // 0
[Link](Number(undefined)); // NaN
[Link](Number('a')); // NaN

let num2 = Number('-123');


[Link](typeof(num2) + " : " + num2); // number : -123

2. parseInt(string, radix)
converts its first argument to a string, parses that string, then returns an integer or NaN.

radix set the base of the string input - range [2, 36] (inclusive).

start from left to right, encounter first non-numerals, truncate.

Note: dot(.) is also non-numerals and therefore will be truncated.

able to retrieve numeral part from a string (truncate numbers) e.g., '123abc' => 123

convert target base to base 10.**


let num = parseInt(string, radix@base);
// e.g., set radix to 16 simply mean the string is of base 16.
// e.g., if string is "a", based on base 16, it will be 10 in base 10 (output)

[Link](parseInt('123')); // 123
[Link](parseInt('123.212431')); // 123
[Link](parseInt(' 123')); // 123
[Link](parseInt(' 1 2 3 ')); // 1
[Link](parseInt(true)); // NaN
[Link](parseInt(false)); // NaN
[Link](parseInt(null)); // NaN

[Link](parseInt("10", 16)); // 16 (but in base 16 => f + 1 = 16)


[Link](parseInt("b", 16)); // 11

[Link](parseInt('10101010', 2)); // 170

// Example 10
parseInt(3, 8); // 3
parseInt(3, 2); //NaN - base 2 has no 3
parseInt(3, 0); // 3 - radix 0 - return input as result or NaN in different browser

3. parseFloat(string)

parse a string argument and returns a floating point number.

dot (.) is not truncated.

[Link](parseFloat('100.2abcd')); // 100.2

[Link](parseFloat('[Link]')); // 123

4. String(mix)

convert any data type to string.


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

[Link](String(null)); // 'null'

[Link](String(123.23)); // '123.23'

[Link](String(true)); // 'true'

[Link](String(123.23ads)); // error! must be a valid data type

5. Boolean(mix)

[Link](Boolean(123)); // true

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

[Link](Boolean(null)); // false

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

[Link](Boolean(" ")); // true

[Link](Boolean("")); // false

6. toString(radix)

convert any data type to string except null and undefined

range [2, 36] (inclusive)

Note: undefined and null cannot be used with toString().

convert base 10 to other base.


[Link]((123).toString()); // must surround number with () else throw error

// convert base 10 to base 8


[Link]((123).toString(8)); //173

// from base 2 to base 10 to base 16


[Link]((parseInt(10101010, 2)).toString(16)); // aa

Implicit Type Conversion


1. isNaN

determines whether a value is NaN, first converting the value to a number if necessary.

type conversion happens implicitly, value that can't be converted to Number is implicitly converted to
false.

[Link](isNaN(NaN)); // true

[Link](isNaN(123)); // false

[Link](isNaN('abc')); // true - implicit conversion of 'abc' to number => NaN

[Link](isNaN(null)); // false - Number(null) => 0 which is number.

2. Increment/ Decrement ++ --

convert value to Number type before operation.

let a = "123";
a ++; // 123

let b = "abc";
b ++; // NaN - Number('abc') -> NaN - note: NaN itself is number type.

3. Unary Plus and Unary Negation (+ -)

Note: must be put in front of an operand without space!


precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't
already.
+x : converts its operand to Number type.
-x : convert its operand to Number type and and negate it

let a = +"abc";
[Link](a + " : " + typeof(a)); // NaN : number

[Link](typeof -'123'); // number

[Link](+null); // 0

[Link](-null); // 0

4. plus operator +

note: plus is special in Js as it is overloaded for two distinct operations: numeric addition and string
concatenation.

When one side/ operand is string, the other side is converted to a string, and then they are
concatenated.

let a = "a" + 1;
[Link](a + " : " + typeof(a)); // a1 : string

//
[Link](1 + 2 + '(5 + 6)');// '3(5 + 6)'

5. - * / %

coerces both operands to numeric value (number type)

let a = "a" * 1; // Number("a") * 1


[Link](a + " : " + typeof(a)); // NaN : Number

6. < > <= >=

comparison operator will convert string to number when one side is a number.

if both side is string, then it will instead compare their ASCII code.
// when comparison involves number type, it converts the non-number to number and compare.
let a = 1 > '2';

[Link](a); // false

let b = 1 > '0';

[Link](b); // true

let c = "10" > 25;

[Link](c); // false

// this compare ASCII


let c = "1" > "2";

[Link](c); // false

7. Equality (==), Inequality (!=) (loosely equality)

let a = 1 == "1"; // true

[Link](typeof a) // boolean

let b = 1 == "2"; //false - convert convert the string to a number. Conversion failure results i

8. AND (&&), OR (||), NOT (!)

Involves the conversion of an operand to Boolean value (during the evaluation process), despite the
final result type is based on the operand it returns.

let a = 1 && 2; // convert 1 to Boolean, if true, move on to the second operand.

Strict Equality (=== & !==)


use === or !== if we don't want type conversion to happen.

But there is a special case:


[Link](NaN === NaN); // false - all NaN values are indistinguishable from each other. https
Examples and Peculiarities

false > true // false

2 > 1 > 3 // true (1) > 3 => false

2 > 3 < 1 // false (0) < 1 => true

10 > 100 > 0 // false (0) > 0 => false

100 > 10 > 0 // true (1) > 0 =>true

// Number(undefined) => NaN

undefined > 0; // false

undefined < 0; // false

undefined >= 0; // false

undefined <= 0; // false

/* when one side is undefined or null, the other side is one of undefined or null, return false

undefined >= undefined; // false

undefined >= null; //false

undefined <= undefined; // false

undefined <= null; // false

// Number(null) => 0

null > 0; // false

null >= 0 // true // 0 >= 0 - implicit type conversion of null to number

null < 0; // false

null <= 0; // true // 0 <= 0 - implicit type conversion of null to number


/* If one of the operands is null or undefined, the other must also be null or undefined to retu

undefined == 0; // false
null == 0; // false - note in equality null is not converted to number and thus it is false. //

undefined == null; // true - both are falsy value by default

undefined === null; // false - with strict equality both are different type (type undefined & ty

// NaN is not equal to any value, including null, undefined, false, true, or an empty string.
undefined == NaN; // false
undefined === NaN; // false
NaN == false; // false
NaN === false; // false
NaN == true; //false
NaN === false; // false
NaN == ""; // false
NaN === ""; // false

({} === {}); // false - both object is at different memory location

var obj1 = {};


var obj2 = obj1;
(obj1 == obj2); // true

Summary
1. NaN is not equal to any value, including itself.
2. plus (+) operation convert number to string for concatenation, while the other operation (-*/%)
converts string to number.
3. typeof(x) print out the data type of x, and the return value is always a string.
4. Comparison between two strings using (> < >= <= == ===) - it is based on ASCII, if compare
between number and string, string is converted to number type and compare.
5. Use strict equality against undefined and null.
6. Value such as false, '', '0', and [] are subject to numeric type coercion, all of them coerce to zero.

Operators
operation => emphasize 'result'
Arithmetic Operators
Addition: has both arithmetic and string concatenation.

"+" operator

4. plus operator

// Arithmetic

// String Concatenation

[Link](1 + '2' + 3); // 123


[Link](1 + 1 + '1' + '(1+3)'); // 21(1+3)

pre-increment vs post-increment

// pre-increment
let a = 10;
++ a; // 11
[Link](a); // 11

//post-increment
let a = 10;
a ++; // 10
[Link](a); // 11
var a = (10 * 3 - 4 / 2 + 1) % 2, // 1
b = 3;

b %= a + 3; // 3

[Link](a++); // 1 (increase after print)


[Link](--b); // 2 (increase first before print)

var a = 123;
var b = 234;

// Exchange value of a and b.

// Hard coding not accepted. What if value of a and b change?


a = 234;
b = 123;

// First - use third variable

var c = a;
a = b;
b = c;

// Second - without third variable

a = a + b;
b = a - b; // (a + b) - b => a
a = a - b; // a + b - (a) => b

Comparison Operators
Relational operators:
<
>
<=
>=

Equality operators:

== : Equality
attempt to convert to the same type and compare if both are different type

=== : Strict equality

consider types
no conversion

!= : Inequality

similar to equality

!== :Strict inequality

similar to strict equality

Comparison of Strings
ASCII

Rules:

1. based on the ASCII value of each characters

let a = 'a' > 'b';


[Link](a); // false
// ascii a => 97
// ascii b => 98
// thus, it should be 'a' < 'b'

2. compare the first character first, if similar, move on to the next and compare.

let b = '10' > '8';


[Link](b); // false
// '10' => 1 (ascii 49) & 0 (ascii 48)
// '8' => ascii 56
// compare first character first '1' > '8' // false (49 > 56)
Comparison of Numbers

let a = 1 === 1; // true

let b = 1 === 2; // false

let c = 1 !== 2; // true

let d = Infinity === Infinity; // true

let e = NaN === NaN; // false why?

Why NaN === NaN is false

Comparison of undefined

let a = undefined === undefined;

Jokes

Logical Operators
Note: the return value can be converted to boolean primitive.

&& AND
AND evaluates operands from left to right, returning immediately with the value of the first falsy
operand it encounters ; if all values are truthy, the value of the last operand is returned.

true if and only if all the operands are true

if encounter falsy expression, return that expression

rule:

1. first expression is evaluated to be true, return second expression as value


2. first expression is evaluated to be false, return first expression.
3. evaluation from left to right.
4. if second operand is a function, function is executed and its value is returned, usually undefined.
// && AND
// look at the first expression (1) first and convert it to boolean value
// if it is true, it moves on
// and return the value of that expression
let a = 1 && 2; // 2
let b = 1 && 2 + 2; // 4
let c = 1 && 0; // 0

// when the first expression is false,


// return the first value.
// the second expression is ignored.
let d = 0 && 3; // 0

// for more expression


let e = 1 && 1 && 1; // 1

let f = 1 + 1 && 1 - 1; // 0

// short-circuit evaluation
2 > 1 && [Link]('a'); // a

// Application of short-circuit evaluation.


const data = ...;
data && fn(data); //if data is meaningful, run [Link](data)

// bitwise AND (&) - compare bit to bit


// bit - 0 and 1
// same - return 1
// different - return 0
// e.g.,
// 0001
// 0010
// 0000 (Ans)
let num = 1 & 2; // 0001 & 0010
[Link](num); // 0000

let num1 = 1 & 3;


[Link](num1);

// work with function

let a = 1;
let b = function () {
[Link]('[Link] is executed');
return 123;
}

let c = a > 0 && b(); // [Link] is executed


[Link](c) // 123

|| OR
OR evaluates operands from left to right, returning immediately with the value of the first truthy
operand it encounters.

true if and only if one or more of its operands is true

if encounter falsy expression, move on to look for truthy expression, if not, evaluate last falsy value it
encounters.

let num = 1 || 3; // 1

let num1 = 0 || 3; // 3

// if both is falsy, return last expression


let num2 = 0 || false; // false

[Link] = funtion (e) {


// browser compatibility
// Non-IE browser, e has value
// IE: e has no value, value in [Link]
let event = e || [Link];
}

Note:
[Link] - You should avoid using this property in new code, and should instead use the Event
passed into the event handler function.

! NOT
NOT returns false if its single operand can be converted to true; otherwise, returns true (negation).

convert value to boolean and negate it.


let a = !123; //!true -> false

let b = !""; //!false -> true

// possible to use more NOT operators


let c = !!""; // !!false -> !true -> false

let d = !undefined; // true

let e = !NaN; // true

let f = !null; // true

falsy value: a value that can convert to false.


undefined, null, NaN, "" (empty string), 0, false

truthy value: a value that can convert to true.


any value except those specified in falsy value.

Comma Operators
evaluates each of its operands (from left to right) and returns the value of the last operand.

var a = (1 - 1, 1 + 1); // return the value of last operand.


[Link](a); // 2

Conditional (ternary) operator


condition? true : false and return value.

var num = 1 < 0 ? 2 + 2 : 1 + 1; // 2

// Note: compare strings - ASCII '10' = '1' & '0' compare with '9' - bit by bit comparison
var num = 1 > 0 ? ("10" > "9" ? 1 : 0) : 2; // 1 > 0 ? (0) : 2; ==> 0
Exercise

// Exercise
var str = false + 1;
[Link](str); // 1
var demo = false == 1;
[Link](demo); // false

// typeof(a) => "undefined" -> true


// -1 + NaN + "" => "NaN" -> true
if (typeof(a) && -true + (+undefined) + "") {
[Link]('nice'); // nice
}
// 11 + Number("11") * 2 == 33
if (11 + "11" * 2 == 33) {
[Link]('nice one'); // nice one
}
// true + false - false => true (overall)
// if true not going to evaluate second expression
!!" " + !!"" - !!false || [Link]('You are pig.') // not executed.

Conditionals
represent decision making

If statement
1. Multiple if statements, each will be evaluated from top to bottom. (waste of performance)
2. chain if-else: if one statement is false, move on to the next statement.
3. multiple else ifs are allowed.

Note: make sure the condition for else if is mutually exclusive.

4. else block is not necessary.


5. nested if statement is allowed.

syntax of conditional statement:


if (condition1) {
/* code to run if condition is true */
} else if (condition2) {

} else if (condition3) {

}else {
/* run if none of the condition is true */
}
if (1 > 0) {
[Link]('I am handsome!'); // condition is true, this code is run.
}

if (1 > 0 && 8 > 9) {


[Link]('Hello'); // condition is false, this code is not run.
}

let score1 = parseInt([Link]('Input:'));

if (score) {
[Link](score);
}

let score2 = parseInt([Link]('Input:'));

// 90 - 100 Apple Google


// 80 - 90
// 70 - 80
// 60 - 70
// 60 and below

// Note: 90 < score < 100 => true < 100 (Please not write like this)

if (score > 90 && score <= 100) {


[Link]('alibaba');
}
else if (score > 80 && score <= 90) {
[Link]('tencent');
}
else if (score > 70 && score <= 80) {
[Link]('baidu');
}
else if (score >= 60 && score <= 70) {
[Link]('mogujie');
}
else if (score < 60) {
[Link]('Oh my god! You gotta be kidding me');
} else {
[Link]('error');
}
if statement and && conversion:

if (1 > 2) {
[Link]('hello');
}

2 > 1 && [Link]('hello'); // if true, execute [Link]('hello')


// note value of function is undefined.

Switch statement
evaluates an expression, matching the expression's value against a series of case clauses, and
executes statements after the first case clause with a matching value, until a break statement is
encountered.

irresponsible - as long as it encounters a matching case, it will execute the following case regardless
of matching case or not.

use when we have exact values to compare for each condition.

not use for comparison of 'greater than' or 'less than'

allow fall through - beware it is a double-edged swords.


let n = 2;

switch (n) {
case 'abc':
[Link]('a');
case 2: // match this
[Link]('b'); // run
case true:
[Link]('c'); // run
}

// use break to stop execution of other case after a matching case.


let n = 2;

switch (n) {
case 'abc':
[Link]('a');
break;
case 2:
[Link]('b');
break;
case true:
[Link]('c');
break;
}

//
let date = [Link]('input');

switch (date) {
/* FALLTHROUGH */
case "monday":
case "tuesday":
case "wednesday":
case "thursday":
case "friday":
[Link]('working');
break;
/* FALLTHROUGH */
case "saturday":
case "sunday":
[Link]('holiday');
break;
}

Loops

for loop
creates a loop that consists of three optional expressions, enclosed in parentheses and separated by
semicolons, followed by a statement (usually a block statement) to be executed in the loop.

for loop is flexible.


// syntax
for (initialization; condition; afterthought) {
statement;
}

// Note: expressions are optional.


// initialization: initialize a counter variable
// condtion -> an expression to be evaluated before each loop - not specified = infinite loop (a
// afterthought -> an expression to be evaluated at the end of each loop iteration - for updatin

for (let i = 0; i < 10; i++) {


[Link]('a');
}

// 1. let i = 0;
// 2. check i < 0; and run code
// 3. i++
// repeat

// take out initialization and afterthought

let i = 0;

for (;i < 10;) {


[Link]('a');
i++;
}

// take out conditional

let i = 1; // i set to 1 - true


let count = 0;
for (;i;) {
[Link]('a');
i++;
if (count === 10) {
i = 0; // i set to 0 - false -> break out of loop
}
}

// without use counter


let i = 1;
for (;i;) {
[Link]('a');
i++;
if (i === 11) {
i = 0
}
}

let count = 0;
for (let i = 0; i < 10; i ++) {
count += i;
}

let i = 100;
for (;i--;) {
[Link](i);
}

// 0 - 100
// divisible by 3, 5, 7
for (let i = 0; i < 100; i++) {
if (i % 3 === 0 || i % 5 === 0 || i % 7 ===0) {
[Link](i);
}
}

while loop
creates a loop that executes a specified statement as long as the test condition evaluates to true.

while loop is a simplified version of for loop.

while (condition)
statement

// infinite loop / never-ending loop


while (1) {
[Link](i);
i ++
}
do while loop
creates a loop that executes a specified statement until the test condition evaluates to false.

The condition is evaluated after executing the statement, resulting in the specified statement executing
at least once.

do {
// body of do-while loop
} while (condition);

let i = 0;
do {
[Link]('a');
i++;
} while (i < 10)

break: terminate the current loop or switch statement and transfers program control to the statemenet
following the terminated statement.

let i = 0;

while(1) {
i++;
[Link](i);
if (i > 100) {
break;
}
}

let sum = 0;
for (let i = 0; i < 100; i ++) {
sum += i;
[Link](i);
if (sum > 100) {
break;
}
}
continue: terminates execution of the statements in the current iteration of the current or labeled loop,
and continues execution of the loop with the next iteration.

for (let i = 0; i < 100; i++) {


if (i % 7 === 0 || i % 10 === 7) {
continue;
}
[Link](i);
}

Function
Function is one of the reference data type.

It is a "subprogram" that can be called by code external (or internal, in the case of recursion) to the
function.

functions are first-class objects, because they can be passed to other functions, returned from
functions, and assigned to variables and properties.

Note: Don't declare function inside if statement.

Why do we need function?


Programming: High coupling (redundancy), low cohesion
-> factor out similar code into a block called function
// basic usage
// without function

if (1 > 0) {
[Link]('a');
[Link]('b');
[Link]('b');
}
if (2 > 0) {
[Link]('a');
[Link]('b');
[Link]('b');
}
if (3 > 0) {
[Link]('a');
[Link]('b');
[Link]('b');
}

// with function

function test() {
[Link]('a');
[Link]('b');
[Link]('b');
//
}

if (1 > 0) {
test()
}
if (2 > 0) {
test()
}
if (3 > 0) {
test()
}

test() // we can even call the function like this

function test() {
let a = 123;
let b = 234;
let c = a + b;
[Link](c);
}

// function as one functionality


function test() {
[Link]('hello world');
}

Function Definition
Function Declaration

// function declaration
function fnName(param) {
// function body
}

// naming using camelCase


function theFirstName() {
}

[Link](theFirstName) // ƒ theFirstName() {} - not memory location as Js cant get it as inte

Function Expression - usually refers to anonymous fn


1. Named fn
2. Anonymous fn *(commonly used)

When using function expression, either named or anonymous, we can't call function by the name of its
function body, we can only call the function by variable name.
// function expression
// note that function name abc is useless when using function expression.
// cannot call this function by abc()
let test = function abc() {
[Link]('a');
}

[Link]([Link]); // abc

// annonymous function
let test = function () {
[Link]('a');
}

[Link]([Link]); // test

Only difference:
[Link]([Link]) get the name of the function body
[Link]([Link]) get the name of the variable.

Note: console in dev tools is like a script at the far bottom of our html, it only run after all our scripts
have done.

Immediately Invoked Function Expression (IIFE)


IIFE

A JavaScript function that runs as soon as it is defined.

IIFE has no declaration.

Use for initializing our application.

We have more interested in the result returned from the function, not the process getting the value.

IIFE behaves just like normal function, it has execution context, and also undergo precompilation.

However, IIFE's don't remain in your function stack, they get popped out, once they a hit a return
statement, or the end of the function block.

Note that it becomes unaccessible after it ends its execution.


// Function declarations occupy memory.
function a() {
// 10000 lines
}

function b() {
// 10000 lines
}

// IIFE
(function (){
var a = 123;
var b = 234;
[Link](a + b);
}())

(function abc (){


var a = 123;
var b = 234;
[Link](a + b);
}())

[Link](abc); //Uncaught ReferenceError: abc is not defined


// Note: even we write name to it, it is unaccessible after use.

// IIFE with return

var num = (function (a, b, c) {


var d = a + b + c
return d;
}(1, 2, 3)) // store IIFE return value, and that IIFE is gone forever.

// IIFE with comma operator


var f = (
function f() {
return "1";
}
, function g() {
return 2;
})
();
typeof f; // 'number'
/*
1. evaluate condition: if (fn) -> if(true)
2. looko at parentheses, (fn) is an expression - meaning after that, it's gone, becomes undefine
*/
var x = 1;
if (function f() {}) {
x += typeof f; // 'undefined'
}
[Link](x); // 1undefined

IIFE Deep Dive

Only expression can be used with function invocation operator xxx(). -> function name is abandoned/
ignored after the expression is executed.

That's why in IIFE the name is always ignored.

Note that defining function has two ways:

1. function declaration
2. function expression.
// Calling function the normal way
function test() {
var a = 123;
[Link](a);
}

test(); // 123 - it works

// What if put () as below?


function test() {
var a = 123;
}() // Uncaught SyntaxError: Unexpected token ')'

// It work with function expression - this is similar to IIFE.


var test = function () {
[Link]('a');
}(); // a

// var test => variable declaratioin


// assign expression (in this case function) to variable test
var test = function () {

}()

// Make function declaration to expression


// with unary plus and negation
+ function test() {
[Link]('a');
}(); // a

- function test() {
[Link]('b');
}(); // b

// with NOT operator


! function test() {
[Link]('c');
}(); // c

// with AND and OR operator


1 && function test() {
[Link]('d');
}(); // d

0 || function test() {
[Link]('e');
}(); // e

// fn name test is abandoned when expression is called.


[Link](test); //Uncaught ReferenceError: test is not defined

// with parentheses - (1 + 1) = 2
// this is an expression, when enclosing with ().
(function test() {
[Link]('a');
})(); // a

// Recommended by W3C**
(function test() {
[Link]('b');
}()); // b
// Note: (1 - 2 + (3 - 1)) - the outer parentheses is executed first.
// In function context, (fn(){}()) outer () makes the function declaration an expression.

IIFE can appear as many form, as long as the function is an expressioin.


// Normal Case without passing argument
function test(a, b, c, d) {
[Link](a + b + c + d);
}(); //Uncaught SyntaxError: Unexpected token ')'

// Case with passing arguments


function test(a, b, c, d) {
[Link](a + b + c + d);
}(1, 2, 3, 4); // Not executed.

/* The above case is interpreted as below*/

function test(a, b, c, d) {
[Link](a + b + c + d);
} // Not executed.

(1, 2, 3, 4); // Comma operator, return the last value, which is 4. (REPL)

/* e.g., let num = (1, 2, 3, 4);


[Link](num); // 4
*/

// Example 9
// 9a
function foo(x) {
[Link](arguments);
return x
}
foo(1, 2, 3, 4, 5); // [1,2,3,4,5]
//9b
function foo(x) {
[Link](arguments);
return x
} (1, 2, 3, 4, 5) // 5
/*
function foo(x) {
[Link](arguments);
return x
} // not executed

(1, 2, 3, 4, 5) // 5
*/

//9c IIFE
(function foo(x) {
[Link](arguments);
return x;
})(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

//9d - apply()
function foo() {[Link](null, arguments)}
function bar(x) {[Link](arguments)}
foo(1, 2, 3, 4, 5);

Parameters & Arguments


Parameter - a placeholder - optional
Arguments - actual value passes into a function

Why parameters?
extend the power of function, allow us to pass value inside function to carry out different type of
operation.

Inside a function there is a local Arguments object : an array-like object accessible inside functions
that contains the values of the arguments passed to that function. As it is an array, we can use loop for
it.

exist in every function.

Arguments length:
use [Link] property that indicates the number of arguments passed to the function.

Parameter length:
use [Link]: length property indicates the number of parameters expected by the
function.
Note: Js allows us to pass infinite amount of arguments into a function.

function test(a, b) {
// implicitly means
// let a;
// let b;
[Link](a + b);
}

test(1, 2); // 1 & 2 are arguments

// Abstract (extract common code as template/ rules)


// reduce duplication
// work like math function

function add(a, b) {
let c = a + b;
[Link](c);
}

// passing argument
add(1, 2);
add(3, 2);

// work with conditionals


function sum(a, b) {
if (a > b) {
[Link](a - b);
} else if (a < 10) {
[Link](a + b);
} else {
[Link](10);
}
}
// Js can accept infinite/ unlimited arguments
function test(a) {
[Link](a);
}

test(1, 2, 3, 4); // output 1 only, note the rest is actually still in an array (arguments objec

function test(a) {
[Link](arguments);
[Link](a);
}
test(1, 2, 3, 4);
// output
// Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol([Link]): ƒ]
// 1

// As arguments object is an array


// we can enumerate it.
function test(a) {
for (let i = 0; i < [Link]; i++) {
[Link](arguments[i]);
}
}

// compare parameter and argument length


function sum(a, b, c, d) {
if ([Link] > [Link]) {
[Link]('more parameter');
} else if ([Link] < [Link]) {
[Link]('more arguments');
} else {
[Link]('equal');
}
}

sum (11, undefined, 3, 'abc'); // note: as js doesn't specify data type, we can pass what we wan

// summation based on infinite arguments.


// without specify the amount of parameters
function sum() {
let result = 0;
for (let i = 0; i < [Link]; i++) {
result += arguments[i];
}
[Link](result);
}
sum(); // 0
sum(1,2,3,4,5,6,7,8,9, 10) // 55

Mapping Case
Js has locale-specific case mapping rules.
Note a & arguments are different variables.
But one of them changes will affect the other to change.
// mapping rule applies
function test(a, b) {
a = 2; // primitive type
arguments[0] = 3; // primitive type
[Link](a);
[Link](arguments);
}
test(1, 2);
/*
output:
3
Arguments(2) [3, 2, callee: ƒ, Symbol([Link]): ƒ]
*/

/*
Special case:
when we don't pass argument to b, meaning that it will not exist inside arguments object.
reassigning b inside function will not help and thus the mapping rule is vanished.
*/
function test2(a, b) {
b = 2;
[Link](arguments[1]);
}
test2(1); // undefined - as mapping rule doesn't apply to b when we don't pass argument into b i

// Example
function b(x, y, a) {
arguments[2] = 10;
alert(a);
}
b(1, 2, 3); // 10

// what if inside the function body has changed to below:


a = 10;
alert(arguments[2]); // 10

Return
ends function execution and specifies a value to be returned to the function caller. - end a function and
give back value.
// 1. End a function execution
function sum(a, b) {
[Link](a);
return; // the function execution ends here.
[Link]('b') // not execute.
}

sum(1); // 1

// Example of return value


let num = Number('123'); // return 123 in number type

// 2. Return value from a function


function num() {
return 123;
}

let num = num(); // store return value in a variable for later use.
[Link](num); // 123

function myNumber(target) {
return +target; // unary plus - convert target to number implicitly
}
let num = myNumber('123');
[Link](typeof(num) + " " + num); // number 123

// Example 1
// x = 1
// y = 0
// z = 0
// add = function add(n) {return n = n + 3}
var x = 1, y = z = 0;

function add(n) {
return n = n + 1; // same as return n
}

y = add(x);

function add(n) {
return n = n + 3; // same as return n
}
z = add(x);

// x = 1
// y = 4 <= 1 + 3
// z = 4 <= 1 + 3
// Note that y and z is not linked.

Recursion
The act of a function calling itself, recursion is used to solve problems that contain smaller sub-
problems. A recursive function can receive two inputs: a base case (ends recursion) or a recursive
case (resumes recursion).

Recursion is limited by stack size.

Recursion uses First In Last Out approach.

Benefit: make code more concise.


Downside: very slow! (first in last out) e.g., factorial(10) is last returned even if it is first called.

Recursion

1. find pattern
2. write return based on pattern
3. write exit - stopping point => based on known value.
/* Factorial
* pattern: n * (n - 1)
* factorial(3) => 3 * factorial(2)
* factorial(2) => 2 * factorial(1)
* factorial(1) => 1 * factorial(0)
* exit when n === 1 ==> 1! & 0! ==> 1
*/
function factorial(n) {
if (n === 0 || n === 1) {
return 1;
}
return n * factorial(n - 1)
}

[Link](factorial(10));

/* Fibonacci - start from 0 and 1


* pattern: n = n-1 + n-2
* fb(5) => fb(4) + fb(3)
* fb(4) => fb(3) + fb(2)
* fb(3) => fb(2) + fb(1)
* fb(2) => 1
* fb(1) => 0
*/

function fibonacci(n) {

if (n === 1) {
return 0;
}
if (n === 2) {
return 1;
}

return fibonacci(n - 1) + fibonacci(n - 2);


}

Callee & Caller


[Link] : refer to the currently executing function inside the function body of that function.

useful for anonymous functions - no name e.g., IIFE.


// Example 1
function test() {
[Link]([Link]);
}

test();
/*
function test() {
[Link]([Link]);
}

*/

// Example 2

function test() {
[Link]([Link]);
function demo() {
[Link]([Link]);
}
demo();
}
test();

/*
ƒ test() {
[Link]([Link]);
function demo() {
[Link]([Link]);
}
demo();
}

ƒ demo() {
[Link]([Link]);
}
*/

// Example 3 IIFE - factorial 100

var num = (function (n) {


if (n == 1) {
return 1;
}
return n * [Link](n - 1);
}(100))

// with named function expression we don't need [Link]


var num = (function test (n) {
if (n == 1) {
return 1;
}
return n * test(n - 1);
}(100))

[Link] : returns the function that invoked this function .

Note: in use strict mode, this is not allowed and throw errors when use.

function test() {
demo();
}

function demo() {
[Link]([Link]);
}
test();
/*
ƒ test() {
demo();
} - meaning: test called the demo fn.
*/

Scope
Scope: the current context of execution in which values and expressions are "visible" or can be
referenced.

Scopes can be layered in a hierarchy, child scopes have access to parent scopes, but not vice versa.

Rule: Local scope can access value from global scope, while global scope can't access value from
local scope.
Global scope: The default scope for all code running in script mode.

Module scope: The scope for code running in module mode.

Function scope: The scope created with a function. **

Block scope: The scope created with a pair of curly braces (a block).

**: focused

// Global scope
let a = 123;

function test() {
// Local scope
let b = 321;
function demo() {
let c = 234;
[Link](b);
[Link](a);
}
}

test();

//

let global = 100; // can be accessed by test & demo

function test() {
let a = 123; // demo can't access
}

function demo() {
let b = 234; // test can't access
}
JavaScript Engine Overview

js

JavaScript interpreter goes through code twice.

1. Parsing

globally scan for syntax errors.


create Abstract Syntax Tree (AST) when valid codes.
throw errors if syntax error, program stops running.

2. Compilation / Precompilation / Creation Phase

involves hoisting.
create variable objects - e.g., Global Object (GO) / Activation Object (AO) = only created during
function invocation.
GO --> Fn invocation --> execution context [AO].
scope - variable objects + scope chain + this.
3. Execution by intepretation

interpreter run through code line by line.


assign values to variables
execute functions and code blocks (conditionals/ loops)
manage call stack: function calls (execution context) are added to callstack / removed from
callstack.

Important Note:

1. For my understanding, step 1 and step 2 is created in the first run, step 3 is the second run.
2. I haven't found the relationship of AST and memory creation phase, thus I am not sure as of now
precompilation is another run, or it is based on the result of AST to create variable objects.

JIT compilation - compile at run time, optimise bytecode (universal to different processors - Intel /
AMD) to machine code - note that machine code is unique to the architecture of our machine - whether
it is intel-based or AMD-based.

Precompilation (Memory Creation Phase)


Js Execution Context and Hoisting
Hoisting:
the process whereby the interpreter appears to move the declaration of functions, variables, classes,
or imports to the top of their scope, prior to execution of the code.

1. Function Hoisting:

hoists the entire function declaration to the top of the current scope.
not work for function expression.

2. Variable Hoisting

declaring a variable anywhere in the code with var is equivalent to declaring it at the top.
only the variable declaration moves to the top of the current scope, not including the value
assignment.
// Reference error
[Link](a) // ReferenceError: a is not defined

/* Variable Hoisting
* Why doesn't this code throw error, instead output undefined?
* The following code behaves as below:
* var a;
* [Link](a);
* a = 123
**/
[Link](a); // undefined
var a = 123;

/* Function hoisting during pre-compilation.


* calling function before its declaration is possible.
* the following code as below:
*
* function test() {
* [Link]('a');
* }
*
* test()
*/

test(); // a

function test() {
[Link]('a');
}

// Example 1
[Link](a); // function a() {}
function a() {}
var a = 123;

Implied globals?

Any variable you don’t declare becomes a property of the global object in JavaScript.

Window: global scope (browser window)

1. Assigning value to a undeclared variable, that variable belong to global object (window).
// a is undeclared but is assigned value.
a = 10; // imply window.a = 10

// Continuous assignment
var = a = b = 123; // a & b belongs to global scope/ global object property.

2. Any declared global variables are properties of the window object.

// Imagine this is a global scope:


var a = 123;
var b = 234; // imply window.b = 234;

// Imagine a & b becomes properties of the window object


window {
a: 123,
b: 234,
...
}

[Link](a); // access window.a


[Link](b); // access window.b

// what if continuous assignment happens inside a function


function test() {
var a = b = 123; // b is being assigned value and it is undeclared - belong to window object.
}

test()
[Link](a); // undefined - a is local-scope variable.

[Link](b); // 123
Precompilation in Function Scope

// Before calling the function


function fn(a) {
[Link](a);
var a = 123;
[Link](a);
function a () {}
[Link](a);
var b = function() {}
[Link](b);
function d() {}
}

1. Create Activation Object (AOB) (scope / execution context)


2. Search for parameters and variable declaration, set them as AO's property, assign undefined to
them

// parameter a & var a;


// var b; <== from function expression
AO {
a: undefined, // a appears twice, but once is enough.
b: undefined,
}

3. Assign argument to parameter

AO {
a: 1, // a set to argument
b: undefined,
}

4. Search for function declaration, set value as function body.

Note: function declaration and function expression is two different concept.


// AO is created!
// function as scope.
AO {
a: function a() {},
b: undefined,
d: function d() {},
}

Note:

1. Last step overrides previous step value.


2. If AO has value, it will use what it has, if it doesn't, it will look for that value from global.
3. Function execution:

// Calling the function -> function execution

function fn(a) {

[Link](a); // function a() {} - from AO object

// past - var a has been hoisted.


var a = 123; // assignment: a = 123; ==> AO {a = 123,}

[Link](a); // 123

function a () {} // passed - have been hoisted.


[Link](a); // 123

// var b has been hoisted.


var b = function() {} // assignment: b = function() {} ==> AO {b = function() {},}

[Link](b); // functoin b() {}

function d() {} // passed - have been hoisted.


}

fn(1); // call the function


// AO during execution
AO {
a: 1,
b: 2,
c: 0,
d: function d() {},
}

function test(a, b) {
[Link](a); // 1
c = 0;
var c;
a = 3;
b = 2;
[Link](b); // 2
function b() {}
function d() {}
[Link](b); // 2
}

test(1);
// AO during execution
AO {
a:123,
b: function () {},
}

function test(a, b) {
[Link](a); // function a () {}
[Link](b); // undefined
var b = 234;
[Link](b); // 234
a = 123;
[Link](a); // 123
function a () {}
var a;
b = 234;
var b = function () {}
[Link](a); // 123
[Link](b); //function () {}
}

test(1);

Precompilation in Global Scope

Note: GO is created first before AO is created.

1. Create an Global Object (GO)

GO === Window Object in browser.

2. Search for parameters and variable declaration, set them as AO's property, assign undefined to
them.
3. Search for function declaration, set value as function body.
// GO during execution
GO {
a: 123;
}

[Link](a); // function a() {}


var a = 123;
function a() {}
[Link](a); // 123
// Example 1
// create first
GO {
test: function test(test) {
[Link](test); // function test() {}
var test = 234;
[Link](test); // 234
function test() {}
}
}

// then AO
AO {
test: 234,
}

function test(test) {
[Link](test); // function test() {}
var test = 234;
[Link](test); // 234
function test() {}
}
test(1);
[Link](test); // function test() {...}
var test = 123;
[Link](test); // 123

// Example 2

GO {
a: function a(a) {...}
}

AO {
a: function () {},
}

[Link](a);

function a(a) {
[Link](a); // 1
var a = 234;
[Link](a); // 234
var a = function () {}
[Link](a); // function () {}
a();
[Link](a); // function () {}

}
var a = 123;
a(1);

// Example 3

GO {
global: 100,
fn: function fn() {...}
}

AO {
// empty
}

var global = 100;

function fn() {
[Link](global); // AO doesn't have global, it will look it up from GO.
}

fn(); // 100

// Example 4

GO {
global: 100,
fn: function fn() {...}
}

AO {
global: undefined; // ==> 200
}

global = 100;
function fn() {
[Link](global); // undefined - undefined is also a value!
global = 200;
[Link](global); // 200
var global = 300;
}

fn();
var global;

// Example 5

GO {
a: undefined,
test: function test() {...},
c: 234,
}

function test() {
[Link](b); // undefined
// pre-compilation doesn't care about if statement, it just retrieve variable declaration.
if (a) {
var b = 100; // if let b = 100; it will be error.
}
[Link](b); // undefined.
c = 234;
[Link](c); // 234
}

var a;
test();

/*
AO {
b: 100,
} */

a = 10; // test is called before a assignment, thus, a is undefined before this step.
[Link](c); //234

// Example 6

AO {
foo: 11,
}
function bar() {
return foo;
foo = 10;
function foo() {

}
var foo = 11;
}
[Link](bar()); // function foo() {}

// Example

GO {
bar: function bar() {...}
}

AO {
foo: 11,
}

[Link](bar()); // 11

function bar() {
foo = 10;
function foo() {

}
var foo = 11;
return foo;
}
// Exercise 1
GO {
a: 100,
demo: function demo(e){},
f: 123,
}

AO {
a: 10,
b: 123, // x -> undefined, as here a is still undefined, can't access value inside if statemen
c: undefined, (function c() {} ) // supposedly undefined,
e: 2,

a = 100;
function demo(e) {
function e() {}
arguments[0] = 2;
[Link](e); // 2
if (a) {
var b = 123;
function c() {} // Note: Now we can't declare function inside if statement, and function in
}
var c;
a = 10;
var a;
[Link](b); // 123 x -> should be undefined.
f = 123;
[Link](c); //undefined
[Link](a); // 10
}
var a;
demo(1);
[Link](a); //100
[Link](f); // 123

// Exercise 2 - value of foo?

// Uncaught SyntaxError: Invalid left-hand side in assignment


[Link] || [Link] = "bar"; // || has more priority than = sign. Thus, [Link] || windo
([Link] || ([Link] = "bar")); // 'bar' - () has more priority first

Scope & Scope Chain


Any object has properties.

Function is a special object, it also has properties.

// Accessible
[Link];
[Link];

// Non-accessible
test.[[scope]]; // Implicit property - store function scope, for Js Engine to use.

Some of which is accessible to us, some is not - only for JavaScript engine to access.

/**
* Function a is defined
* it is born with properties like name,
* and [[scope]]
*
* */
function a() {}
var glob = 100;
a();

[[Scope]]

Lexical Environment vs Execution Context

Note: Lexical environment ~> scope.

[[scope]] stores a collection of execution context called scope chain.

This hidden [[scope]] is a property of the function, created at declaration, not invocation.
Execution Context

Global execution context -> Global Object (GO)

Function execution context -> Activation Object (AO)

Before function execution, it will create an execution context, including Activation Object - part of
execution context.

This executioin context defines an environment during which the function executes.

When function is invoked, it forms a new execution context.

Each execution context is destroyed after function execution.


function test() {}

test(); --> newExecutionContext - AO{} -> destroyed


test(); --> newExecutionContext - AO{} -> destroyed

Scope Chain
Scope chain: a list of all those parent variable objects, plus (in the front of scope chain) the function’s
own variable/activation object.

a collection of execution context (itself) and parents' execution context .**

Look for variable in scope chain, where contain AO and parent Variable Object (GO / AO). **

scope chain = [variable object + all parent scopes - variable object]

Rule: if a variable is not found in the own scope (in the own variable/activation object), its lookup
proceeds in the parent’s variable object, and so on.

This explains that why outer function cannot access variables in inner function, while the inner function
can access outer function variables. **

Variable Objects

A container of data asscoiated with the execution context - store variables and function declaration
defined in the context.

In global context, variable object is the Global Object (GO) itself.

Activation Objects

In function context, a variable object is called an Activatioin Object (AO).


fn Definition: 0: bAO, 1: cAO

fn Execution: 0: aAO (self) --> 1: bAO --> 2: cAO


Note: --> chain/ link

When fn execution is ended, its own execution context is destroyed, but its parent execution contexts
are kept. That fn is back to its definition state, awaiting the next execution to be invoked and new
execution context is formed.**
// Example 1 - use own variable first if available.
var a = 234;
function test() {
var a = 123;
[Link](a); // 123 - as test fn has its own a with a value of 123
}
test();

/** Example 2
* Function definition a.[[scope]] -->
* 0: {GO}
* */
function a() {}
var glob = 100;
/**
* Function execution a.[[scope]] -->
* 0: AO {} - new AO places at the head of the chain.
* 1: GO {}
* */
a();

// Example 3
function a() {
function b() {
var b = 234;
}

var a = 123;
/* 2
* When b is executed,
* bAO is created
* place before its parent (fn a) scopo chain
*/
b();
}

var glob = 100;

/* 1
* When fn a is executed -> b is defined.
* fn b is born inside the scope of a.
* fn b has fn a scope chain (aAO + GO)
*/
a();

Q: Does aAO in fn b scope chain identical to aAO in fn a scope chain?


=> yes, they are identical, b is using fn a AO's reference.

Q: When does a function ends its execution?


=> when the statement inside the function is executed. Once finished, the execution context of that
function is also destroyed.

function a() {
function b() {
var bb = 234;
aa = 0; // can b change aa value?
}
var aa = 123;
b();
[Link](aa); // 0 - yes, it changed. fn a give reference of its AO to fn b.
}
var glob = 100;
a();
/*Exercise 1
* note: GO/AO represents execution context - including GO & AO.
* a definition a.[[scope]]: 0: GO
* a execution a.[[scope]]: 0: aAO, 1: GO
* b definition b.[[scope]]: 0: aAO, 1: GO
* b execution b.[[scope]]: 0: bAO, 1: aAO, 2: GO
* c definition c.[[scope]]: 0: bAO, 1: aAO, 2: GO
* c execution c.[[scope]]: 0: old cAO, 1: bAO, 2: aAO, 3: GO
* c execution c.[[scope]]: 0: new cAO, 1: bAO, 2: aAO, 3: GO
*/

function a() {
function b() {
function c() {

}
c();
c(); // the previous cAO is destroyed, now the new cAO is created.
}
b();
}
a();

// Note: only when a is called, we can access its contents (variables, function etc.)
// e.g., fn a execution results in fn b definition.

Closure
Whenever a function returns an inner function, that returned inner function is a closure.

Note that inner function that has returned is still able to access variables of its outer function scope.

Closure causes supposedly destroyed execution context to be unreleased, lead to memory leak .

Memory Leak:a type of resource leak that occurs when a computer program incorrectly
manages memory allocations in a way that memory which is no longer needed is not released

Note: Memory leak is similar to memory concumption - fails to return allocated memory. If memory
leak, the remaining space is less.

Disadvantage: Make loading time longer - especially those accidentally created closure .
When a closure is formed?

Nested function and an inner function is returned -> to global scope.


if a function can go to outside, it is also a closure.

Note: During function a execution, it creates function b definition and return function b. Then, it
discards its AO once finished, however, function b - an inner function of function a that get
returned and stored in global scope still holds a reference to the aAO. Thus, function b still has
access to function a variables. Note that anything stored in global scope is not destroyed until the
HTML documents has finished execution.
// Example 1
// fn a definition
// a.[[scope]] => 0: GO

function a () {
function b() {
var bbb = 234;
[Link](aaa);
}
var aaa = 123;
return b; // note: return reference to fn b.
}
var glob = 100;
// fn a execution
// a.[[scope]] => 0: aA0 1: GO
// fn b definition
// b.[[scope]] => 0: aA0 1: GO
var demo = a(); // b - fn b is returned and stored in demo - it forms a closure.
// fn b (demo) execution
// b.[[scope]] => 0: bAO 1: aAO 2: GO - note b still contains aAO, that's supposedly destroyed w
demo(); // b() // 123

// Example 2
// fn a definition
// a.[[scope]]: 0: GO
function a() {
var num = 100;
function b() {
num ++;
[Link](num);
}
return b; // return fn b
}
// fn a execution
// a.[[scope]]: 0: aAO, 1: GO
// fn b definitioin
// b.[[scope]]: 0: aAO, 1: GO
var demo = a(); // fn b
// fn b execution
// b.[[scope]]: 0:bAO, 1:aAO, 2:GO
demo(); // 101
// b.[[scope]]: 0:new bAO, 1:aAO, 2:GO
demo(); // 102 - note: aAO is not destroyed, num is still there.
// Example 3
function makeCounter() {
// `i` is only accessible inside `makeCounter`.
var i = 0;

return function() {
[Link]( ++i );
};
}

// Note that `counter` and `counter2` each have their own scoped `i`.

var counter = makeCounter();


counter(); // logs: 1
counter(); // logs: 2

var counter2 = makeCounter();


counter2(); // logs: 1
counter2(); // logs: 2

i; //Uncaught ReferenceError: i is not defined

// Example 4 - Problem **
function test() {
var arr = [];
for (var i = 0; i < 10; i ++) {
// this is an assignment statement.
// arr[i] - i here changes because it is executed.
arr[i] = function () {
[Link](i); // function is not executed now, i remains i, system doesn't know what's i
}
}
return arr; // [ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ]
}
var myArr = test();

for (var j = 0; j < 10; j ++) {


myArr[j](); // 10 10 10 10 10 10 10 10 10 10 why? Each fn forms a closure with test. And i is
}

// Example 4 Solution with IIFE


function test() {
var arr = [];
for (var i = 0; i < 10; i ++) {
// IIFE
(function (j) {
// every IIFE will have a unique j.
arr[j] = function () {
[Link](j); // inner function can still access j of the IIFE, even IIFE is gone.
}
})(i);
}
return arr;
}
var myArr = test();

for (var j = 0; j < 10; j ++) {


myArr[j]();
}

// Example 4 Solution with let keyword

function test() {
var arr = [];
// variable declared with let is local to the loop
for (let i = 0; i < 10; i++) {
arr[i] = function () {
[Link](i);
}
}
return arr;
}

var myArr = test();


for (var j = 0; j < 10; j++) {
myArr[j]();
}

// Example 5

function test() {
var temp = 100;
function a() {
[Link](temp);
}
return a;
}
var demo = test();
demo(); // 100

// Closure without using return


var demo;
function test() {
var abc = 100;
function a () {
[Link](abc);
}
demo = a;
}
test();
demo();

Closure Usage

1. realization of public variable.

not depend on outer variable.


// Without Closure - we need global variable.
var count = 0;

function count() {
count ++;
[Link](count);
}

// With closure, counter


function count() {
var count = 0;
function add() {
count++;
[Link](count);
}
return add;
}
var counter = count();
counter();
counter();
counter();
counter();
counter();
counter();

2. resemble caching - a storage structure

a powerful technique used in JavaScript to store and retrieve frequently accessed data, reducing
the need for repeated computations or expensive operations.
// Example 1
function test() {
var num = 100; // shared by fn a and fn b.
function a() {
num ++;
[Link](num);
}
function b() {
num --;
[Link](num);
}
return [a, b];
}
var myArr = test();
myArr[0](); //101
myArr[1](); //100

// Example 2
function eater() {
var food = ""; // acts as an implicit storage structure
var obj = {
eat: function() {
[Link]("I am eating " + food);
food = "";
},
push: function (myFood) {
food = myFood;
}
}
return obj;
}

var eater1 = eater();


[Link]('banana');
[Link]();

3. Encapsulation, private property


// Example 1
function Deng(name, wife) {
// this is the private variable can't be easily accessed outside.
var prepareWife = 'xiaozhang';
[Link] = name;
[Link] = wife;
// this function is returned to outside and thus forms a closure.
[Link] = function () {
[Link] = prepareWife;
}
[Link] = function (target) {
prepareWife = target;
}
// unless we set a method that can reveal the private variable.
[Link] = function () {
[Link](prepareWife);
}
}
var deng = new Deng('deng', 'xiaoliu');

// Example 2
var inherit = (function() {
var F = function () {}; // private variable
return function (Target, Origin) {
[Link] = [Link];
[Link] = new F();
[Link] = Target;
[Link] = [Link];
}
}());

function Father() {}
function Son() {}
inherit(Son, Father);
[Link] = 'Deng';
var son = new Son();
var father = new Father();

[Link] = 'male';
[Link]([Link]); // 'male'
[Link]([Link]); // undefined
4. Modular programming - avoid 'Polluting' the global variables

var name = 'bcd';


var init = (function () {
var name = 'abc';

function callName() {
[Link](name);
}
return function () {
callName();
}
}())

var initDeng = (function () {


var name = 123;
function callName() {
[Link](name);
}
return function () {
callName();
}
}())

init(); // abc
initDeng(); // 123

Objects
store various keyed collections and more complex entities.

function inside object is called method.


var mrDeng = {
name: '[Link]',
age: 30,
health: 100,
sex: 'male',
smoke: function () {
[Link]('I am smoking! cool!');
[Link] --},
drink: function () {
[Link]('I am drinking');
[Link] ++},
}
// reference itself, we can use this
var mrDeng = {
name: '[Link]',
age: 30,
health: 100,
sex: 'male',
smoke: function () {
[Link]('I am smoking! cool!');
[Link] --},
drink: function () {
[Link]('I am drinking');
[Link] ++},
}

[Link]();
[Link]([Link]);
[Link]();
[Link]([Link]);

Accessing Object Properties


Internally, transform dot notation to bracket notation.

[Link] --> obj['prop']

Both are equivalent. But with different use case. Note that dot notation has certain case it can't deal
with.

Conclusion: Performance wise, bracket notation is faster, and more flexible.


1. [Link]

var obj = {
name: 'abc',
}

[Link]([Link]);

2. obj["prop"]

var obj = {
name: 'abc',
'has-car': true,
}

[Link](obj['name']);
[Link](obj[`has-car`]);

// Example
var deng = {
wife1 : {name : "xiaoliu"},
wife2 : {name : "xiaozhang"},
wife3 : {name: "xiaomeng"},
wife4 : {name: "xiaowang"},
sayWife : function (num) {
return this['wife' + num]; // realise string concatenation!
}
}
Create, Read, Update, Delete (CRUD) of Property

var mrDeng = {
name: '[Link]',
age: 30,
health: 100,
sex: 'male',
smoke: function () {
[Link]('I am smoking! cool!');
[Link] --},
drink: function () {
[Link]('I am drinking');
[Link] ++},
}

// Create
[Link] = 'xiaoliu';

// Read
[Link]([Link]);

// Update
[Link] = 'female';

// Delete
delete [Link];
[Link]([Link]); // undefined - although name is not existed anymore, no error thrown.*

// Example
var deng = {
name: 'laodeng',
sex: 'male',
gf: 'xiaoliu',
prepareWife: 'xiaowang',
wife: "",
divorce: function () {
delete [Link];
[Link] = [Link];
},
getMarried: function () {
[Link] = [Link];
},
changePrepareWife: function (someone) {
[Link] = someone;
}
}

Ways to Create Objects


Compared to other languages like Java and C++, JavaScript object is more flexible, we can add
property and delete as we wish. Other languages requires a class as blueprint to create instances of
object.

1. Object Literal

var obj = {};

2. Constructor Function - as Factory

new operator: create an instance of a user-defined object type or of one of the built-in object types that
has a constructor function.
// Built-in - like factory, creating similar object but independent of each other
Object();
Array();
Number();

// Customized - use new to create instance


var obj = new Object(); // same as var obj = {};

[Link] = 'abc';
[Link] = 'female';
[Link] = function () {
[Link]('Hello');
}

// Constructor Function name must be PascalCase


function Car (color) {
[Link] = color;
[Link] = 'BMW';
[Link] = '1400';
[Link] = '4900';
[Link] = 1000;
[Link] = 100;
[Link] = function () {
[Link] --;
}

var car = Car(); // a function call - return undefined.

// Create the first instance of Car


var car1 = new Car('red'); // return an object**
[Link] = 'Merz';
[Link]();
[Link]();
[Link]; // 98

// Create the second instance of Car


var car2 = new Car('green'); // return an object**
[Link] = 'Maserati';
[Link]();
[Link]; // 99
function Student(name, age, sex) {
[Link] = name;
[Link] = age;
[Link] = sex;
[Link] = 2023;
}

var student1 = new Student('wx', 23, 'male');

var student2 = new Student('jy', 22, 'female');

3. [Link](proto, propertiesObject);
create objects with a designated prototype and also some properties.

second parameter is optional


// Example 1
var obj = {name: 'sunny', age: 123};
var obj1 = [Link](obj);

// Example 2
[Link] = 'sunny';
function Person() {}
var person = [Link]([Link]);

// Example 3 - pass with second argument


o = [Link]([Link], {
// foo is a regular data property
foo: {
writable: true,
configurable: true,
value: "hello",
},
// bar is an accessor property
bar: {
configurable: false,
get() {
return 10;
},
set(value) {
[Link]("Setting `[Link]` to", value);
},
},
});

Internal Mechanism of a Constructor Function


1. Implicitly add an empty this object, this = {} at the top of the function body when we call a
function with new operator.
2. Execute [Link] = xxx .
3. Implicitly return this.

Note: we must have new operator preceding our function call to create object, otherwise it is just
regular function call.
AO {
this: {name: xxx, age: yyy, sex: zzz,}
}

function People(name, age, sex) {


// var this = {
// name: "",
// age: "",
// sex: "",
// }
[Link] = name;
[Link] = age;
[Link] = sex;
// return this;
}

// Example 2

function Person(name, height) {


// var this = {}
[Link] = name;
[Link] = height;
[Link] = function () {
[Link]([Link]);
}
// return this;
}

[Link](new Person('wx', 180).say());

// Example 3 - model how the mechanism work. - just for modelling, don't do this.

function Person(name, height) {


var that = {};
[Link] = name;
[Link] = height;
return that;
}

var person = Person('wx', 180);


var person2 = Person('jy', 160);
// Example 4 - if we explicitly return an empty object?

function Person(name, height) {


// var this = {}
[Link] = name;
[Link] = height;
[Link] = function () {
[Link]([Link]);
}
return {};
}

var person = new Person('jy', 160);


[Link](person); // {}

// Example 5 - if we explicitly return a primitive value?

function Person(name, height) {


// var this = {}
[Link] = name;
[Link] = height;
[Link] = function () {
[Link]([Link]);
}
return 123; // return primitive value is not allowed here **
}

var person = new Person('jy', 160);


[Link](person); // Person {name: 'jy', height: 160, say: ƒ} - thus it still return 'this'.
Wrapper Classes

Primitive data type has no properties and methods.


// Number has two types.
// primitive number
var num = 123; // primitive value - don't have properties and methods.
[Link](num); // 123

//Number Object - also number


var num = new Number(123);
[Link](num); // Number {123}

// add property is allowed.


[Link] = 'a';
[Link]([Link]); // 'a'
// it can perform arithmetic operation
[Link](num * 2); // 246 - note: the result is primitive.

// String

var str = "";

var str = new String('abcd');


str.a = 'bcd';
[Link] = function () {return this.a}
[Link]([Link]()); // 'bcd'

// Boolean

var bol = new Boolean(true); //Boolean {true}


var bol = new Boolean(false); //Boolean {false}
var bol = new Boolean('');// Boolean {false}
var bol = new Boolean('false'); // Boolean {true}

// undefined & null


// both of them can't have properties.

When we add property to primitive type, it generally won't raise error, and implicitly call new Number(),
new String(), new Boolean() for us and assign the property to this new Primitive Object. After this, it
deletes the object.
// Wrapper Object
// Example 1
var str = 'abcd';
// new String('abcd').length
[Link]([Link]); // 4 - it is from Number Wrapper Object
[Link] = '123';

// Example 2
var num = 4;
// new Number(4).len = 3; ---> delete
[Link] = 3;
// new Number(4).len --> undefined
[Link]([Link]); // undefined

// Example 3
// In array this is working, can it work with string?
var str = [1,2,3,4,5];
[Link] = 2;
[Link](str); // [1,2]

// With String
var str = 'abcd';
// new String('abcd').length = 2; --> delete
[Link] = 2;
[Link](str); // 'abcd'

// Example 4

var str = 'abc';


str += 1;
var test = typeof(str);
// new String(test).length -> 6
if ([Link] == 6) {
[Link] = 'typeof return value might be String'; // new String(test).sign = '...'; --> delet
}
// new String(test).sign
[Link]([Link]); // undefined

// Example 5
var a = 5;
function test() {
a = 0;
alert(a);
alert(this.a);
var a;
alert(a);
}

test(); // 0 -> 5 -> 0


var test1 = new test(); // 0 -> undefined (this.a is not assigned a) -> 0

// Example 6
function employee(name, code) {
[Link] = 'wangli';
[Link] = 'A001';
}

var newemp = new employee('zhangming', 'A002');


[Link]('emp name:' + [Link]); // wangli - due to hardcode.
[Link]('emp id:' + [Link]); // A001 - due to hardcode.

// Example 7 - closure and constructor function


function Person(name, age, sex) {
var a = 0;
[Link] = name;
[Link] = age;
[Link] = sex;
function sss() {
a ++;
[Link](a);
}
[Link] = sss; // this inner function is returned, forming a closure
}

var oPerson = new Person();


[Link](); // 1
[Link](); // 2

// execute constructor function again - form a new execution context


var oPerson1 = new Person();
[Link](); // 1 <== new instance - new closure.

Prototype (Ancestor of Objects)


Every object has a built-in property called its prototype.
prototype: an object also.

each instance has access to properties and methods we add to its prototype - inheritance.

Note: If constructor function has a similar property or method, instance will use that instead of its
prototype.

// Before Person constructor function, [Link] already exist.


// [Link] = {} - empty object - ancestor of Person
[Link] = 'hehe';
[Link] = 'Deng';
[Link] = function () {
[Link]('Hi');
}
function Person (name, age, sex) {
[Link] = 'Ji'
[Link] = name;
[Link] = age;
[Link] = sex;
}

var person = new Person('a', 16, 'female');


var person2 = new Person('b', 17, 'male');

// instance inherits properties from prototype


[Link]([Link]); // hehe
[Link]([Link]); // hehe
// if constructor function has, use what it has.
[Link]([Link]); // Ji
[Link]([Link]); // Ji

// Another constructor function


function Fish () {
[Link] = 'fish';
}

var fish = new Fish();


[Link]([Link]); // undefined - which means that the prototype is linked to own const

Benefit of prototype:

1. Reduce redundancy: prototype has only one, add common properties to prototype reduce the
need to run those properties every time creating new instances.
// Example 2 - Use prototype to reduce redundancy
[Link] = 1400;
[Link] = 4900;
[Link] = 'BMW';

function Car(color, owner) {


[Link] = owner;
[Link] = color;
}

var car = new Car('red', '[Link]');

// Access public properties from their prototype.


[Link]([Link]); // 1400
[Link]([Link]); // 4900
[Link]([Link]); // 'BMW'

// Example 2 - another way to write prototype


[Link] = {
height: 1400,
lang: 4900,
carName: 'BMW',
}
function Car() {

var car = new Car();


[Link]([Link]); // 1400
[Link]([Link]); // 4900
[Link]([Link]); // 'BMW'

Create, Read, Update, Delete in Prototype


Q: Can we perform CRUD operation on instance to change its prototype?

Impossible for create, update and delete unless it is reference type. Read depends. We usually add
properties or methods via its prototype.
// Create
[Link] = 'Deng';
// Update
[Link] = 'James';
function Person(name) {
[Link] = name;
}
// Delete
delete [Link]; // this delete [Link]

function Person(name) {
[Link] = name;
}

var person = new Person('wx');

// Can we modify prototype from instance?

// Create
[Link] = 'Too'; // No, It means adding a new property.

// Read
[Link]([Link]);// 'Deng' - we can access prototype LastName from instance, provide

// Update
[Link] = 'James'; // No, try to reassign value, it will add a new property to itself, n

// Delete
delete [Link]; // it only remove its property LastName.

delete [Link]; // Once delete its LastName, can we now delete its [Link]?

What's inside prototype?


Check constructor
1. we can access prototype using [Link] and note that inside there is an constructor.
2. we can change constructor inside prototype!

function Car() {
[Link] = 'BMW';
}

var car = new Car();

[Link]([Link]);
/*ƒ Car() {
[Link] = 'BMW';
}*/

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

// Note we can change constructor in prototype!


function Person() {}

[Link] = {
constructor: Person;
}

Check prototype
Every object has prototype pointed to its prototype.

Note: Previously [[Prototype]] is __proto__ in Chrome Dev tool. Adding underscore means it is
private and we should not touch it.

__proto__ is a simple accessor property on [Link]


[Link] = 'abc';
function Person () {
// Initially, we say "this" is empty object, but it actually has a __proto__.
// If trying to access a property, if the property is not found, it will use indexes pointed t
// var this = {
// __proto__: [Link]
// };
}
var person = new Person();

[Link](person); // Person {}
// Old, deprecated way.
[Link](person.__proto__);
// modern way
[Link]([Link](person));

[Link]([Link]); // abc - through proto, get name from [Link]

We can modify instance prototype


// Modify prototype

function Person() {
// this = {
// __proto__: [Link]
//}
}

var obj = {
name : 'sunny',
}

var person = new Person();


// we can modify prototype of instance.
person.__proto__ = obj;
[Link]([Link]);
[Link](person.__proto__); // note that the prototype is no longer [Link], but obj

// What happens to another instance?


var person2 = new Person();
[Link](person2.__proto__); // Note that the prototype of this instance is still [Link]
// Example 1 - change prototype property
[Link] = 'sunny';
function Person() {}
var person = new Person();
[Link] = 'cherry';
[Link]([Link]); // cherry

// Example 2 - change prototype property


[Link] = 'sunny';
function Person() {}
[Link] = 'cherry';
var person = new Person();
[Link]([Link]); // cherry

// Example 3 - change prototype


[Link] = 'sunny';
function Person() {
// var this = {__proto__:[Link]}
}
var person = new Person();
// change prototype
[Link] = {
name: 'cherry',
};
[Link]([Link]); // cherry (x) -> sunny: Because person still hold the reference to Per

/* Simple illustration
var obj = {name: 'a'};
var obj1 = obj;
obj = {name: 'b'};

[Link] = {name:'a'};
__proro__ = [Link];
[Link] = {name: 'b'};
*/

// Example 4 - the order matter


[Link] = 'sunny';
function Person() {
// vasr this = {__proto__: [Link]}
}
[Link] = {
name :'cherry',
}
var person = new Person();
[Link]([Link]); // cherry

Prototype Chain
Prototype can have prototype that links as a chain.

The chain end is when we reach a prototype that has null for its own prototype - [Link] is
the end.

// Prototype Chain
// What is the prototype of Grand?
// [Link].__proto__ ==> [Link]
[Link] = 'Deng';
function Grand() {}

var grand = new Grand();

[Link] = grand;
function Father() {
[Link] = 'xuming';
}

var father = new Father();

[Link] = father;
function Son () {
[Link] = 'smoke';
}
var son = new Son();
[Link]([Link]); // ƒ toString() { [native code] }

// Where is this toString coming from? [Link] - ancestor of Grand.

CRUD
read: [Link].__proto__
delete & add: must through itself, not its descendant.
// delete
delete [Link];
// add
[Link] = yyy;

update:
primitive type or other overriding behaviour is not allowed.
reference type is special, adding something to reference type is allowed.

// update
[Link] = zzz;

// The only case where update works with object is when working with a reference type value
[Link] = 'xxx'; // it modify [Link] & doesn't add a new property to
// Example 1
function Father() {
[Link] = 'xuming',
[Link] = {
card1: 'visa',
}
}

var father = new Father();

[Link] = father;
function Son() {
[Link] = 'smoke';
}

var son = new Son();

[Link] = 100; // try to override the entire {card1: 'visa'} by 100


[Link]([Link]); // 100 - add a new property of son.
[Link]([Link]); // {card1: 'visa'} - remains changed

// Example 2 **
function Father() {
[Link] = 'xuming',
[Link] = {
card1: 'visa',
}
}

var father = new Father();

[Link] = father;
function Son() {
[Link] = 'smoke';
}

var son = new Son();


// access inside of fortune
// add a new property to reference type fortune.
[Link].card2 = 'master';
[Link](son); // Son {habit: 'smoke'}
[Link](father); // {name: 'xuming', fortune: {…}}
[Link]([Link].card2); // master - changed
// update existing property in reference type fortune

[Link].card1 = 'changed';
[Link]([Link].card1); // changed
// Example
function Father() {
[Link] = 100;
}

var father = new Father();

[Link] = father;
function Son() {
[Link] = 'smoke';
}

var son = new Son();

[Link] ++; // [Link] = [Link] + 1 take out and add 1 for itself -> mean add a new property to
[Link]([Link]); // 101
[Link]([Link]); // 100

// Example 2
// 'this' inside sayName fn points to those who use this sayName fn.
[Link] = {
name : 'a',
sayName: function () {
[Link]([Link]);
}
}

function Person() {
[Link] = 'b';
}

var person = new Person();


[Link]([Link]()); // b - this points to person who uses it
[Link](); // a - this point to [Link] who uses it

// Example 3
[Link] = {
height : 100,
}

function Person () {
[Link] = function () {
[Link] ++;
}
}

var person = new Person();


[Link]();
[Link](person); // Person {height: 101, eat: ƒ}
[Link](person.__proto__); // {height: 100} - prototype remains unchanged

// Example 4
[Link] = 100;
function Fish() {}

var fish = new Fish();


[Link] ++;
[Link](fish); // 101
[Link](fish.__proto__); // 100

Does every object have prototype?


Most objects inherit from [Link], there's exception for object created with
[Link](null) .

As prototype is an implicit/ private property, man-made prototype for object created with
[Link](null) is useless.

Note: If system does give us prototype, then we can modify whatever we like. In the case of
[Link](null) , it originally has no prototype, thus any behavior to assign a prototype to it is
going to be futile.

var a = [Link](); // VM52:1 Uncaught TypeError: Object prototype may only be an Object or

var b = [Link](123); // error too.

var obj = [Link](null);

obj.__proto__ = {name: 'a',};

[Link]([Link]); // undefined - if an object originally has no prototype, system won't rec


[Link]
Since undefined and null has no prototype, thus they have no toString()

[Link] has toString(),


[Link] also has toString() as well, but with different functionality. Since [Link] is
the ancestor of Number, thus [Link] override [Link].

Note that [Link]() is not as useful as [Link]()

Why modify [Link] does not work?


/*
[Link]
[Link] // overriden
[Link] // use [Link]
[Link] // overriden
[Link] // overriden
*/

// Example 1- Why undefined and null can't call toString()?

[Link](); // TypeError: Cannot read properties of undefined (reading 'toString')


[Link](); // TypeError: Cannot read properties of null (reading 'toString')

// Example 2 - toString() from Number

[Link](); // SyntaxError: Invalid or unexpected token - as system think after dot (.) must

var num = 123;


[Link](); // '123' - new Number(num).toString();

// Example 3 - toString() from [Link]


var obj = {};
[Link](); // '[object Object]'

// Example 4 - call [Link] for Number and Boolean.

[Link](123); // [object Number] - not as useful

[Link](true); // [object Boolean] - not as useful

// Example 4 - override Number prototype toString


[Link] = function () {
return 'Hi I\'ve change [Link]';
}

var num = 123;

[Link]([Link]());// 'Hi I change [Link]'

[Link](num); // 123 - this [Link] cant be overriden.


// Example 5 - Implicit calling toString
// toString is only called if the value is an object.

var obj = 123;


[Link](obj); // 123 -> number is primitive.

var obj1 = {};


[Link](obj); // [object Object]

var obj2 = [Link](null);


[Link](obj2); // TypeError: Cannot convert object to primitive value - obj2 has no toStr

var obj3 = [Link](null);


[Link] = function() {
return 'Hi';
}
[Link](obj3); // Hi - as it must call toString method, even it is created by us.

Call & Apply


equivalent to normal function call

Both replace/ specify the value of this inside a function / constructor function with whatever value we
want.

One Difference:

Call: pass arguments (Arg1...ArgN) individually

Apply: pass an array as the argument only.

Call

Call() method of a Fn calls this Fn with a given this value and arguments provided individually

[Link](thisArg, arg1, ..., argN)

use:
borrow constructor function for encapsulation of thisArg - bundling properties and methods of that
constructor function.

e.g., thisArg is an empty object.


// Function call with () and .call()

function test() {
[Link]('Hello');
}
test() // 'Hello' --> similar to [Link]();
[Link]()// 'Hello'
// Example 1 - Encapsulation of obj using other constructor function
function Person(name, age) {
// this === obj: obj replaces this inside Person
[Link] = name; // [Link] = name;
[Link] = age; // [Link] = age;
}

var person = new Person('wx', 24);

var obj = {};


/*Conventionally, we write it like this
[Link] = name;
[Link] = age;
*/
[Link](obj, 'wx', 24); // similar Person()

[Link](obj); // {name: 'wx', age: 24}

// Example 2 - encapsulation of one constructor function using another consturctor function


function Person(name, age, sex) {
// [Link] = name;
// [Link] = age;
// [Link] = sex;
[Link] = name;
[Link] = age;
[Link] = sex;
}

function Student(name, age, sex, tel, grade) {


// this = {__proto__: [Link], name: '', age: '', sex: ''}
[Link](this, name, age, sex);
[Link] = tel;
[Link] = grade;
}

var student = new Student('sunny', 123, 'male', 139, 2017);


// Example 3
function Wheel(wheelSize, wheelStyle) {
[Link] = wheelSize;
[Link] = wheelStyle;
}

function Seat(c, seatColor) {


this.c = c;
[Link] = seatColor;
}

function Model(height, width, length) {


[Link] = height;
[Link] = width;
[Link] = length;
}

function Car(wheelSize, wheelStyle, c, seatColor, height, width, length ) {


// this = {__proto__: xxx, }
// use other constructor function to build up properties of Car
[Link](this, wheelSize, wheelStyle);
[Link](this, c, seatColor);
[Link](this, height, width, length);
}

var car = new Car(100, 'styled', 'leather', 'Black', 1800, 1900);

Apply

[Link]() calls this function with a given this value, and arguments provided as an array

[Link](thisArg, [argsArray])
function Wheel(wheelSize, wheelStyle) {
[Link] = wheelSize;
[Link] = wheelStyle;
}

function Seat(c, seatColor) {


this.c = c;
[Link] = seatColor;
}

function Model(height, width, length) {


[Link] = height;
[Link] = width;
[Link] = length;
}

function Car(wheelSize, wheelStyle, c, seatColor, height, width, length ) {


// this = {__proto__: xxx, }
// use other constructor function to build up properties of Car
[Link](this, [wheelSize, wheelStyle]);
[Link](this, [c, seatColor]);
[Link](this, [height, width, length]);
}

var car = new Car(100, 'styled', 'leather', 'Black', 1800, 1900);

Exercise

function foo() {
[Link](null, arguments)
}

function bar(x) {
[Link](arguments)
}

foo(1, 2, 3, 4, 5)
Inheritance
History of Inheritance
1. Traditional --> Prototype Chain

inherit useless properties is the issue.

usage or performance wise not good.

[Link] = 'Ji';
function Grand() {
[Link] = 'hehe';
}
var grand = new Grand();

[Link] = grand;
function Father() {}
var father = new Father();

[Link] = father;
function Son() {}
var son = new Son();

2. Constructor Stealing

not technically an 'inheritance'

call / apply

can't steal the prototype of the borrowed constructor function.

run the consturctor function implicitly run more than one function in a run.

write less code, good


performance-wise, not good.
function Person(name, age, sex) {
[Link] = name;
[Link] = age;
[Link] = sex;
}

function Student(name, age, sex, grade) {


[Link](this, name, age, sex);
[Link] = grade;
}

var student = new Student();

3. Shared Prototype **

[Link] = [Link]

Downside: can't simply modify own prototype because it is shared.

Note: must inherit before use.


// Example 1
[Link] = 'Deng';
function Father() {}

function Son() {}

[Link] = [Link];

var son = new Son();

// Example 2
function inherit(Target, Origin) {
[Link] = [Link];
}

function Father() {}
function Son() {}
inherit(Son, Father);
var son = new Son();
var father = new Father();
// Downside
[Link] = 'male'; // it also mess up [Link].

4. Inheritance via intermediary

use an intermediate constructor function as a bridge.

child can inherit from prototype but also have right to modify own prototype.

[Link] = [Link]
[Link] = new F();

Note: child get constructor from Ancestor, we need to override it ourselves. *****

child. __proto__ ==> new F(). __proto__ ==> [Link]


function inherit(Target, Origin) {
function F() {};
[Link] = [Link];
[Link] = new F();
// let Target keeps its constructor*****
[Link] = Target;
// inherit from who?
[Link] = [Link];
}

function Father() {}
function Son() {}
inherit(Son, Father);
[Link] = 'Deng';
var son = new Son();
var father = new Father();

[Link] = 'male';
[Link]([Link]); // 'male'
[Link]([Link]); // undefined

// Another way of writing inherit using IIFE and closure **


var inherit = (function() {
var F = function () {}; // private variable
return function (Target, Origin) {
[Link] = [Link];
[Link] = new F();
[Link] = Target;
[Link] = [Link];
}
}());

function Father() {}
function Son() {}
inherit(Son, Father);
[Link] = 'Deng';
var son = new Son();
var father = new Father();

[Link] = 'male';
[Link]([Link]); // 'male'
[Link]([Link]); // undefined
[Link]([Link]); // {lastName: 'Deng'}

Method Chaining

var deng = {
smoke : function () {
[Link]('Smoking ... cool!');
return this;
},
drink : function () {
[Link]('drinking ...cool!');
return this;
},
perm : function () {
[Link]('perming ... cool');
return this;
}
}

Object Enumeration (for...in loop)


iterates over all enumerable string properties of an object (ignoring properties keyed by symbols),
including inherited enumerable properties.

1. get all own string keys of the current object


2. check property descriptor of each key
enumerable: visit and marks as visited.
not enumerable: not vist, but marks as visited.
shadowed / overriden properties are only visited one.
3. current obj is replaced with their prototype and the process repeats.

Note:

1. if there is multiple objects in the prototype chain having a property with the same name, only the
first one encountered will be considered.
2. enumeration can continue down the prototype chain.

use hasOwnProperty() to limit access further down prototype chain. **

3. property added to the current object/ prototype during iteration is never visited.
4. delete and update works as expected- highly dependent on where we put the code. **
5. modify property descriptor of a property during first loop won't take effective during that loop,
although its property descriptor has been changed. It will take effective on the second loop and so
on. (unexpected) **
// Enumeration of Array
var arr = [1, 3, 3, 4, 6, 7 , 8, 9];

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


[Link](arr[i]);
}

// Enumeration of Object

var obj = {
name: '13',
age: 123,
sex: 'male',
height: 180,
weight: 75,
}

for (var prop in obj) {


[Link](prop + " " + typeof(prop));
}

/*
name string
age string
sex string
height string
weight string
*/

// Example

var obj1 = {
a: 123,
b: 234,
c: 345,
}

for (var prop in obj1) {


obj1[prop] ++;
[Link](obj1[prop]);
}
/*
124
235
346
*/

// Example 1 - common mistake!


var obj2 = {
a: 123,
b: 234,
c: 345,
}

var prop;
for (prop in obj2) {
[Link]; // undefined - implicitly convert [Link] --> obj2['prop'], and obj2 doesn't have
}

// Example 2 - common mistake! ***


var obj2 = {
a: 123,
b: 234,
c: 345,
prop: 123,
}

var prop;
for (prop in obj2) {
[Link]; // 123 - implicitly convert [Link] --> obj2['prop'] thus accessing obj2's prop p
}

// Example 3 - common trap

var obj = {
name : '123',
age : 123,
sex : 'male',
height : 180,
weight : 75,
__proto__ : {
lastName : 'deng',
try: 123,
__proto__: {
lastName: 'haha',
try2: 456,
__proto__: {
firstName: 'No',
try3: 789,
lastName: 'George',
}
}
}
}

for (var prop in obj) {


[Link](obj[prop]);
}
/*
123
123
male
180
75
deng - only the first 'lastName' is considered.
123 - try
456 - try2
No
789 - try3
*/

// Example 4 - prevent enumerating down the prototype chain, limit it to the current object only
var obj = {
name : '123',
age : 123,
sex : 'male',
height : 180,
weight : 75,
__proto__ : {
lastName : 'deng',
try: 123,
__proto__: {
lastName: 'haha',
try2: 456,
__proto__: {
firstName: 'No',
try3: 789,
lastName: 'George',
}
}
}
}
for (var prop in obj) {
if ([Link](prop)){
[Link](obj[prop]);
}
}

/*
123
123
male
180
75
*/

// Example 5 Add property before iteration

const obj = {
a : 1,
b : 2,
}

obj.c = 3; // allow

for (var prop in obj) {


[Link](obj[prop]);
}

/*
1
2
3
*/

// Example 6 Add property during iteration

const obj = {
a : 1,
b : 2,
}

for (var prop in obj) {


// obj.c = 3; - no print
[Link](obj[prop]);
// obj.c = 3; - no print
}

// Example 7 Add property to prototype during iteration

const proto = {};


const obj = { __proto__: proto, a: 1, b: 2 };

for (const prop in obj) {


// __proto__.c = 3; - no print
[Link](obj[prop]);
// __proto__.c = 3; - no print
}

/*
1
2
*/

// Example 8 Delete property

const obj = {
a : 1,
b : 2,
}

// delete obj.a; - no print a - already deleted


for (var prop in obj) {
// delete obj.a; - no print a - already deleted
[Link](obj[prop]);
// delete obj.a; - print a - print before delete is possible.
}

// Example 9 Change property value


const obj = { a: 1, b: 2 };
// obj.b = 123 - print new b
for (const prop in obj) {
// obj.b = 123; - print new b
[Link](obj[prop]);
// obj.b = 123; - print new b
}

// Example 10 Change property descriptor


const obj = { a: 1, b: 2, c: 3 };
// [Link](obj, "c", { enumerable: false }); - no print c, enumerable set to false
for (const prop in obj) {
// [Link](obj, "c", { enumerable: false }); - still print c even if enumerable
[Link](`obj.${prop} = ${obj[prop]}`);
// [Link](obj, "c", { enumerable: false }); - still print c even if enumerable
}
/* First loop result
obj.a = 1
obj.b = 2
obj.c = 3
*/

for (const prop in obj) {


[Link](`obj.${prop} = ${obj[prop]}`);
[Link](obj, "c", { enumerable: false });
}
/* Secpmd loop result
obj.a = 1
obj.b = 2
*/

1. hasOwnProperty(prop) check if the current object has the specific property and not inherited from
its prototype.

var obj = {
height: 123,
name: 'abc',
__proto__: {
age: 123,
}
}
[Link]([Link]('height')); // true

[Link]([Link]('age')); // false - as it is inherited from its prototype.


2. in operator : returns true if the specified property/ method is in the specified object or its
prototype chain

use case: check if we can use properties/ method on this object - (including its prototype properties)

// 'prop' in obj

var obj = {
height: 123,
name: 'abc',
__proto__: {
age: 123,
}
}

[Link]('height' in obj); // true


[Link]('age' in obj); // true - even if it is from its prototype

3. instanceof : see if the prototype property of a constructor appears anywhere in the prototype
chain of an object

check if object's prototype chain contain Constructor Function's prototype property

object instanceof Fn

use: check if an object or an array.

use:
// object instanceof ConstructorFunction

// Example 1
function Person() {}

var person = new Person();

var obj = {};

[Link](person instanceof Person); // true

[Link](person instanceof Object); // true

[Link](obj instanceof Person); // false - obj has no [Link] in its prototype chai

[Link](person instanceof Array); // false - because [Link] is not existed within p

[Link]([] instanceof Array); // true

[Link]([] instanceof Object); // true

[Link](obj instanceof Array); // false - obj prototype chain has no [Link]

Differentiate Object and Array


1. constructor

var obj = {};


var arr = [];

[Link]([Link]); // ƒ Object() { [native code] }


[Link]([Link]); // ƒ Array() { [native code] }
[Link]([Link] !== [Link]); // true

2. instanceof
var obj = {};
var arr = [];
[Link](arr instanceof Array); // true
[Link](obj instanceof Array); // false **

3. call

mechanism: call / apply replace this inside a function / method with the value we passed as the first
argument, e.g., object, array, number, string etc.

[Link]([]); // pass array in call, this inside the toString will be set

// Example of internal mechanism of [Link] method


[Link] = function () {
// 1. recognis this => [] replace original this
// 2. return corresponding result
}

var obj = {};


var arr = [];

[Link]([Link](arr)); // [object Array]


[Link]([Link](obj)); // [object Object]
[Link]([Link](arr) !== [Link](obj)); // tru

This
1. During the precompilation or memory creation phase, a function's this points to the window
object.
function test(c) {
// var this = [Link]([Link])
// {
// __proto__: [Link];,
//}
var a = 123;
function b () {}
}

AO {
arguments: [1],
this: window,
c: 1,
a: undefined,
b: function() {}
}

test(1); // this points to window


new test(1); // with new, this points to [Link]([Link])

2. in the global scope, this also refers to the window object.


3. call / apply method can alter the context to which this refers during the execution of a
function.

function Person(name, age){


// now this refers to obj
[Link] = name;
[Link] = age;
}

var obj = {};


[Link](obj, 'wx', 24); // alter this inside constructor function

4. When invoking a method using [Link]() , this keyword within the method refers to the
object itself
var obj = {
a: function () {[Link]('hi')},
}

obj.a(); // who call a, this refers to who - obj


Exercise

// Example 1
var name = '222';
var a = {
name: '123',
say: function () {
[Link]([Link]);
}
}
var fun = [Link];
fun(); // 222 - Regular function call; 'this' refers to the global object
[Link](); // 123 - 'this' refers to 'a' object because it's called as a method of 'a'

var b = {
name: '333',
say: function (fun) {
[Link](this);
fun();
test();
}
}

function test() {
[Link](this);
}

[Link]([Link]);
/*
[Link](this); ==> b {...}
fun(); ==> 222 - Regular function call inside '[Link]'; 'this' still refers to the global object
test(); ==> window {...} - a regular function call, referring to window
*/
[Link] = [Link];
[Link](); // 333

// Example 2

var a = 5;

function test() {
// this = [Link]([Link])
a = 0;
alert(a);
alert(this.a);
var a;
alert(a);
}

test();
/*

AO {
a : 0,
this:window
}

0
5
0
*/
new test();
/*
AO {
a : 0
this: {}
}

0
undefined - as this.a is not assigned any value
0
*/

// Example 3
var foo = 123;
function print() {
// var this = [Link]([Link]);
[Link] = 234;
[Link](foo); // as inside print doesn't have foo, it goes to global scope and find foo wh
}
new print(); // 234 x => 123 - because [Link] inside print is no longer refer to window and th

// Example 4
var foo = '123';
function print() {
var foo = '456';
[Link] = '789'; // this refers to window object's foo.
[Link](foo); // this refers to local scope foo.
}

print(); // 456

// Example 5
function print() {
[Link](foo);
var foo = 2;
[Link](foo);
[Link](hello);
}
print();

/*
undefined
2
ReferenceError: hello is not defined
*/

// Example 6
function print() {
var test;
test();
function test() {
[Link](1);
}
}
print(); // 1

// Example 7
function print() {
var x = 1;
if (x == "1") [Link]('One!');
if (x === "1") [Link]('Two!');
}
print(); // One!

// Example 8
function print() {
var marty = {
name: "marty",
printName: function () {[Link]([Link]);}
}
var test1 = {name: "test1"};
var test2 = {name: "test2"};
var test3 = {name: "test3"};
[Link] = [Link];
var printName2 = [Link]({name: 123});
[Link](test1); // test1
[Link](test2); // test2
[Link](); // marty
printName2(); // 123 **
[Link](); // test3
}

print();

// Example 9
var bar = {a : "002"};
function print() {
bar.a = 'a';
[Link].b = 'b';
return function inner() {
[Link](bar.a);
[Link](bar.b);
}
}

print()();
// 'a'
// 'b'

Clone
A has {}
B also want A's {} but has no relationship with A's {}
Shadow Copy

// Example
var obj = {
name: 'abc',
age: 123,
sex: 'female',
card: ['visa', 'master'],
}

var obj1 = {};

function clone (origin, target) {


var target = target || {};
for (var prop in origin) {
target[prop] = origin[prop];
}
return target;
}

clone(obj, obj1);

[Link](obj === obj1); // false

[Link] = 'wx';
[Link]([Link]); // abc
[Link]([Link]); // wx

// Issue with shallow copy


// both obj and obj1 are sharing the same reference for the card array.
[Link]('unionpay');
[Link]([Link]); //['visa', 'master', 'unionpay']
[Link]([Link]); //['visa', 'master', 'unionpay']

Deep Copy
consider array and object
recursion
var obj = {
name: 'abc',
age: 123,
sex: 'female',
card: ['visa', 'master'],
wife: {
name: 'abc',
age: 25,
wife1: {name: 'a', age: 30,},
wife2: {name: 'b', age: 25,},
wife3: {name: 'c', age: 28,},
}

var obj1 = {};

// enumeration
// 1. check if primitive
// 2. check if array or object
// 3. create corresponding array or object
// recursion

function deepClone(origin, target) {

var target = target || {};


var toStr = [Link];
var arrStr = '[object Array]';

for (var prop in origin) {


if ([Link](prop)) {
if (origin[prop] !== "null" && typeof(origin[prop]) === 'object') {
/* if ([Link](origin[prop]) === arrStr) {
target[prop] = [];
} else {
target[prop] = {};
} */
target[prop] = ([Link](origin[prop])) === arrStr ? [] : {};
deepClone(origin[prop], target[prop]);
} else {
target[prop] = origin[prop];
}
}
}
return target;
}

deepClone(obj, obj1);

Array
zero-indexed

Definition
two ways. There are technically the same.

1. array literal / array initializer

Sparse arrays - intentionally reserve some space.

[Link] - include empty slot we left intentionally

// array literal
var arr = [];

// Example

var arr = []; // [] - an empty array

// Sparse arrays - reserve space


var arr = [,,]; // [empty × 2]

var arr = [1,,1]; // [1, empty, 1]


arr[1]; // undefined

var arr = [1,2,,,,,7,8];


[Link]([Link]); // 8

2. constructor

Special case: if passing one argument and that argument is integer number, this returns a new array
instance with its length property set to that number.
RangeError: when there's one argument that is a number but its value is not an integer or not between
0 and 232 - 1 (inclusive).

// constructor
var arr = new Array();

// Example

var arr = new Array('a'); // ['a']

var arr = new Array(null); // [null]

var arr = new Array(undefined); // [undefined]

var arr = new Array(1, 2, 3); // [1, 2, 3]


[Link]([Link]); // 3

// One argument - number


var arr = new Array(0); // []
[Link]([Link]); // 0
var arr = new Array(10); // [empty × 10] - empty arr with length 10

var arr = new Array(10.2); // RangeError: Invalid array length

Read and Write of Array


array is quite tolerant of errors.

var arr = [1, 2, 3];


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

var arr = [];


arr[10] = 'a';
[Link](arr); // [empty × 10, 'a'] - it will expand accordingly
Array method (ES3.0)
Change original array
1. push: adds the specified elements to the end of an array and returns the new length of the array.

var arr = [];


[Link](10);
[Link](11);
[Link](12);
[Link]([10, 11, 12]);

//

var arr = [];

// demo: we can override array method


[Link] = function () {
for (var i = 0; i < [Link]; i ++) {
this[[Link]] = arguments[i];
}
return [Link];
}

2. pop: removes the last element from an array and returns that element. - parameter: None

var arr = [1, 2, 3, 4];

[Link](); // 4
[Link](); // 3
[Link](arr); //[1, 2]

3. unshift: adds the specified elements to the beginning of an array and returns the new length of the
array. - parameter: element1...elementN

var arr = [1,2,3];

[Link](5, 6, 7); // 6

[Link](arr); // [5, 6, 7, 1, 2, 3]
4. shift: removes the first element from an array and returns that removed element. - parameter:
None
5. reverse
6. splice
7. sort

bubble sort
var arr = [2,1,6,3,2,9];
[Link](); // [1, 2, 2, 3, 6, 9]

var arr = [-1,2,1,2,3,5];


[Link](); // [-1, 1, 2, 2, 3, 5]

var arr = [1, 3, 10, 3, 1, 2];


[Link](); // [1, 1, 10, 2, 3, 3] - unexpected result

/*
1. must write parameter
2. return
a. - return value: num in front put in front
b. + return value: num behind put in front
c. 0 no action
*/

// Example with comparison function (ascending order)


var arr = [1, 3, 10, 3, 1, 2];

[Link](function (a, b) {
if(a > b) {
return 1;
} else {
return -1;
}
});

[Link](arr)// [1, 1, 2, 3, 3, 10]

// Example (descending order)


var arr = [1, 3, 10, 3, 1, 2];
[Link](function (a, b) {
if(a < b) {
return 1;
} else {
return -1;
}
});

[Link](arr)// [10, 3, 3, 2, 1, 1]

// Example (ascending simplified)


// concept:
// a > b
// a - b > 0
var arr = [1, 3, 10, 3, 1, 2];

[Link](function (a, b) {
return a - b;
});

// Example (descending simplified)


var arr = [1, 3, 10, 3, 1, 2];

[Link](function (a, b) {
return b - a;
});

// Exercise 1: make an ordered array out of order.

var arr = [1, 2, 3, 4, 5, 6, 7];

[Link](function (a, b) {
return [Link]([Link]()) ? a - b: b - a;
});
// more unbiased and higher degree of randomness
[Link](function (a, b) {
return [Link] - 0.5;
});

// Exercise 2 - sort based on age


var cheng = {
name: 'cheng',
age: 18,
sex: 'male',
face: 'handsome',
}
var deng = {
name: 'deng',
age: 40,
sex: 'undefined',
face: 'amazing',
}
var zhang = {
name: 'zhang',
age: 20,
sex: 'male',
face: 'good',
}

var arr = [cheng, deng, zhang];


[Link](function (a, b) {
return [Link] - [Link];
});

// Exercise 3: based on string length


var arr = ['abc', 'bcd', 'cccc', 'dddd', 'adassdfcdsfsd', 'afdssdfsewfwefew', 'sefrse', 'edfrse

[Link](function (a, b) {
return [Link] - [Link];
});

// Exercise 4: based on byte length


var arr = ['abc', 'bcd', 'cccc', 'dddd', 'adassdfcdsfsd', 'afdssdfsewfwefew', 'sefrse', 'edfrse

[Link](function (a, b) {
//...
});

No change original array


1. concat: merge two or more arrays

var arr = [1, 2, 3];


var arr2 = ['a', 'b', 'c', 'd'];
var arr3 = [true, false];
var newArr = [Link](arr2);
var newArr2 = [Link](arr2, arr3);
[Link](newArr); // [1, 2, 3, 'a', 'b', 'c', 'd']
[Link](newArr2); // [1, 2, 3, 'a', 'b', 'c', 'd', true, false]
[Link](arr); // [1, 2, 3]
[Link](arr2); // ['a', 'b', 'c', 'd']

2. toString: returns a string representing the specified array and its elements.
var arr = [1, 2, 3, 'a', true];
[Link]([Link]()); // '1, 2, 3, 'a', true'

3. slice: returns a shallow copy of a portion of an array into a new array object selected from start to
end (end not included) where start and end represent the index of items in that array.

var arr = [1,2,3,4,5];


var a = [Link]();
var b = [Link](2, 4);
[Link](a); // [1,2,3,4,5] - shallow copy
[Link](b); // [3, 4] - shallow copy
[Link](arr); // [1,2,3,4,5]

4. join: creates and returns a new string by concatenating all of the elements in this array, separated
by commas or a specified separator string. We can specify separator.

var arr = [1,2,3,4,5];


var str = [Link]();
var str2 = [Link]('-');
[Link](str); // "1,2,3,4,5" - separated by comma
[Link](str2); // "1-2-3-4-5" - separated by customized separator

Note: Performance wise, using [Link] is better than string concatenation method. String is primitive
and stored in stack, taking out from stack and concatenate one by one is extremely inefficient, while
array is a reference type, stored in heap and the data is obtained via hashing.

5. split: takes a pattern and divides this string into an ordered list of substrings by searching for the
pattern, puts these substrings into an array, and returns the array.

var str = "1-2-3-4-5";


var newArray = [Link]('-');
[Link](newArray); // ['1', '2', '3', '4', '5']

Array-like Object
an object that has indexed properties and a length property.

use properties to mirror array specificity.


allow us to dynamically update length - if we add a push method in it, it can update length
accordingly

It doesn't inherit methods from [Link], unless we add to it on our own.

The array object observes the length property, and automatically syncs the length

Advantages:

1. has feature of both array and object

Example

1. DOM
2. Arguments object
// Example 1
var obj = {
"0" : "a",
"1" : "b",
"2" : "c",
"3" : "d",
"length": 4,
"push": [Link],
"splice": [Link],
}
[Link](obj); // ["a", "b", "c", "d"] - but currently chrome console it displays as {0: 'a',

// Example 2 - arguments object


function test() {
[Link](arguments);
[Link]();
}
test(1,2,3,4,5,6); // TypeError: [Link] is not a function

// Example 2
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"length": 3,
"push": [Link],
"splice": [Link],
}

// Example 3 - quirk behavior


// the quirk can be explained by how [Link] works fundamentally.
var obj = {
'2' : 'a',
'3' : 'b',
length: 2,
'push': [Link], // let's say the array-like object has a 'push'
}
/* Quirk explained
[Link] = function (target) {
this[[Link]] = target
[Link] ++
}
What really happens?

[Link] = function (target) {


obj[[Link]] = target // obj[2] = 1 => thus '2' value changes to 1!
[Link] ++;
}
*/

[Link](1);
[Link](2);
[Link](obj); // { '2': 1, '3': 2, length: 4, push: [Function: push] }

// Example 4 - iterate all the properties of an array-like object


var obj = {
"0": "a",
"1": "b",
"2": "c",
name: "abc",
age: 123,
length: 3,
push: [Link],
splice: [Link]
}

for (var prop in obj) {


[Link](obj[prop]);
}

/*
a
b
c
abc
123
3
ƒ push() { [native code] }
ƒ splice() { [native code] }
*/

Try...Catch
useful to handle unexpected errors - when we're not sure.
prevent throwing error if an error occurs that stop the execution of the line following the error line.

try: act as normal block until an error is found and pass the execution to the catch block.

catch: catch error that usually throw on the console, and thus the programme is not terminated.

allow us to handle error message on our own.


tolerant of error.
error: error name & error message

// Code without try catch


// code at the error line and after the error line is not executed.
[Link]('a');
[Link](b); // error
[Link]('c');
[Link]('d');
// a
// ReferenceError: b is not defined

// with try catch


try {
[Link]('a');
[Link](b); // error - stop
[Link](c); // not execute
} catch(e) {
[Link]([Link] + " : " + [Link]); // never execute unless error occurs in try block
}
[Link]('d'); // still execute
// a
// ReferenceError : b is not defined <= from catch block
// d

error is unexpected.

e.g., when receiving data from backend

Q: when does the data come?


Q: Is the data transfer successful?
Q: Is the internet stable?
etc.
// Example

var data = null; // from backend

[Link](data);

Error Name
Note: A programmer spends 3 / 4 times debugging.

1. EvalError: use of global eval()

2. RangeError: when a value is not in the set or range of allowed values


3. RefereneError: when a variable that doesn't exist (or hasn't yet been initialized) in the current
scope is referenced.
4. SyntaxError: incorrect use of a pre-defined syntax and it's detected while compiling or parsing
source code
5. TypeError: when an operation could not be performed, typically (but not exclusively) when a value
is not of the expected type
6. URIError: when URI (URL) encoding or decoding wasn't successful

Use Strict (ES5.0)


EcmaScript version:
3.0
5.0
version update: may lead to conflict between syntax of old and new version.

How to solve conflict between ES3 and ES5?

browser is based on ES3.0 version + addtional methods from ES5.0 by default.


Conflict of old methods between ES3 and ES5 -> standardized by using ES3.
What if we want to use ES5 to resolve part of the conflict? ES5.0 'use strict'
with 'use strict', based on ES5. Otherwise, based on ES3.

use strict
with strict mode, browser no longer support es3 non-standardized sytax and use the latest standard.

flexibility becomes lower, but the chance of error is also lower.

syntax: write 'use strict' at the top of the code or function body to enable ES5 standard.

two types of strict mode:

1. global
2. local

Note: No other codes before 'use strict'!

usage:

1. if company requires us to write in strict mode. -> global


2. to ensure our code to perform with more precision and not affect other people code. -> local
(recommended)

Question: why does the strict mode use "use strict" string to enable it?

If a function like strict() is used to enable strict mode, there's risk of error, especially those
older browser that has compatibility issue.
the benefit of string -> fully support by all browser versions - string being a string.
for browser compatibility and as a fall back.
old browser - even though not supporting and recognizing strict mode, it won't raise error.
new browser - able to recognise and enable strict mode.

ES 5.0 standard:

1. [Link] / [Link]/ [Link] property is not allowed

Note: arguments object is not the same as arguments property. arguments object is still working.
// global strict mode
"use strict";
function test() {
[Link]([Link]);
}
test(); // error

// local strict mode


function demo() {
[Link]([Link]);
}
demo(); // f demo() {...}

function test() {
"use strict";
[Link]([Link]); // error
}
test();
demo(); // not executed due to error in the previous line.

2. with is not allowed


with can modify the top of the scope chain.

It is powerful. But ...

As it can directly modify scope chain, which is a structure that is formed through a very complicated
internal operations. It requires the engine to sacrifice performance to modify it, causing the program to
be very slow.

Thus, ES5.0 is not allowed the use of with that lower performance.
// Example 1
var obj = {
name: 'obj',
age: 234,
}

var name = 'window';

function test() {
var age = 123;
var name = 'scope';
with (obj) {
[Link](name); // obj
[Link](age); // 234
}
}

// Example 2 - simplify code with namespacing


var org = {
dp1: {
jc: {
name: 'abc',
age: 123,
},
deng: {
name: 'xiaodeng',
age: 234,
}
},
dp2 : {

}
}

with ([Link]) {
[Link](name); // abc
}

with ([Link]) {
[Link](name); // xiaodeng
}

// Example 3 - simplify code of document object


with(document) {
write('a'); // no longer need ```[Link]('a')```
}

// with strict mode:


"use strict";
with(document) {
write('a'); // no longer need ```[Link]('a')```
}

3. variable assignment must come after variable declaration

"use strict";
var a = b = 3; // ReferenceError: b is not defined

4. this

In strict mode, this during precompilation phase is no longer referring to window.


// global this
"use strict";
[Link](this); // window {}

// non-strict mode
function Test() {
[Link](this);
}

Test(); // Window {...}

new Test(); // Test {}

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

[Link](123); // Number {123} - wrapper object

// strict mode
"use strict";

function Test() {
[Link](this);
}

Test(); // undefined - before strict mode, it refers to window

new Test(); // Test {}

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

[Link](123); // 123 - number primitive type

5. No redundant properties and parameters

In ES3, redundant properties or parameters are not throwing errors.

Note: object with duplicated property still not raise error in ES5.0 strict mode, although based on
standard it is strictly not allowed. It might throw error in the future.
// Example 1
// non-strict mode
function test (name, name) {
[Link](name);
}
test(1); // undefined
test(1, 2); // 2

// strict mode
"use strict";
function test (name, name) { // error
[Link](name);
}
test(1);
test(1, 2);

// Example 2
// non-strict mode
var obj = {
name: '123',
name: '234',
}
[Link]([Link]); // 234

// strict mode
"use strict";
var obj = {
name: '123',
name: '234',
}

[Link]([Link]); // 234 - still not raise error but based on standard it is not allowed. M
6. eval function
eval: evaluates JavaScript code represented as a string and returns its completion value.

It may change the scope.

Note: ES3.0 and ES5.0 banned the use of eval.

// ES3.0
var a = 123;
eval('[Link](a)'); // error

// ES5.0 strict mode


"use strict";
var a = 123;
eval('[Link](a)'); // error

//
"use strict";
var global = 100;
function test() {
var global = 200;
eval('[Link](global)');
}

test();

Date Object
usually, we don't use method containing Coordinated Universal Time (UTC).

day (day of week) and month starts from zero index. **

getYear and setYear has been replaced by getFullYear and setFullYear.


Date().getTime() is very useful. **

var today = new Date(); // current date and time


var day = [Link](); // day of week (e.g., 1 => Monday)
var year = [Link]();
var month = [Link]();
var date = [Link](); // day of month (e.g., 18)
var hour = [Link]();
var minute = [Link]();
var second = [Link]();
var millisecond = [Link]();
var timestamp = [Link]();

usage:
measure a programme's performance.

var start = new Date().getTime();


for (var i = 0; i < 100000000; i++) {
[Link]('hello world');
}
var end = new Date().getTime();
[Link](`elapsed time: ${end - start} ms`); // elapsed time: 10578 ms

Scheduling a Call
part of window object => thus this inside refers to window.

setTimeout(fn, time): execute code after a time delay.


setInterval(fn, time): execute code in fn for a specific time interval
clearTimeout(id): cancel the execution of setTimeout
clearInterval(id): cancel the execution of setInterval

Note:

1. setTimeout and setInterval returns a timer identifier that is used to cancel the timer / execution.
2. time in millisecond(ms)
3. ID pool is shared between setTimeout and setInterval, and each id must be unique.
4. passing fn without calling operator() only.
5. passing string of codes rather than fn is possible, but not recommended.
6. setTimeout & setInterval is not precise or accurate.
Q: is using clearTimeout reset the id?
Nope, the specific id holds by particular timer function is only used to stop its execution and
nothing more. Remember each timer holds an unique id, thus defining the next timer will be
assigned a new id. We can still [Link] the old timer id.

var timerId = setTimeout(function() {


[Link]('hi');
}, 1000);

clearTimeout(timerId)

usage:

1. as a timer

var minInput = [Link]('input')[0];


var secInput = [Link]('input')[1];
var secCount = 0;
var minCount = 0;
var timer = setInterval(function () {
if (minCount === 3) {
[Link]('The time is up.')
clearTimeout(timer);
}
[Link]('value', secCount);
[Link]('value', minCount);
// [Link] = secCount;
// [Link] = minCount;
secCount ++;
if (secCount >= 60) {
secCount = 0;
minCount ++;
}
}, 1000);

Javascript Object Notation (JSON)


use to transfer data
between frontend and backend.

Note: object is for locally use while JSON is for data transfer.

XML
similar to HTML, but can customize tag.

the way storing data resembles object.

<student>
<name>deng</name>
<age>40</age>
</student>

JSON
another format of storing data.
similar to javascript object
property name must be quoted by double quotation mark ("xxx").

{
"name": "deng",
"age": 123,
}

data transfer format:

// JSON string - use to transfer data in the web


'{"name": "deng","age": 123}'
Convert JSON
1. [Link](obj)

var obj = {
name: 'wx',
age: 23,
}

var jsonString = [Link](obj);

2. [Link](str)

var jsonString = '{"name": "deng","age": 123}';

var json = [Link](jsonString);

Revision

Wrapper
1. Primitive data type can't have properties or methods.

var num = '123';


[Link]([Link]); // 3 - due to internal implementation of wrapper obj -> new String(num

2. Adding new property to Primitive data type won't cause error.


Note:

var num = 123;


// new Number(num).abc; --> delete
[Link] = 'abc';
// new Number(num).abc
[Link]([Link]); // undefined

3. Primitive data type is immutable.


var str = '123';
str[1] = 3;
[Link](str); // '123'

Prototype

[Link] = 'deng';
function Person() {
// var this = {
// __proto__: [Link]
//}
}

// [Link](proto, config): config -> definedProperty


var demo = {
lastName: 'deng',
}
var obj = [Link](demo);
obj = {
__proto__: demo,
}

Two ways of creating properties:

1. a variable declared using var is added as a non-configurable property of the global object.

its property descriptor cannot be changed and it cannot be deleted using delete

var num = 123;


[Link]([Link]); // 123
delete [Link]; // false
[Link]([Link]); // 123

2. global variable directly attached to window object is configurable.


it can be deleted.

[Link] = 123;
[Link]([Link]); // 123
delete [Link]; // true
[Link]([Link]); // undefined
This and Call
1. precompilation this--> window
2. this refers to who invokes the function / method

var name = 'window';


var obj = {
name: '222',
say: function () {
[Link]([Link]);
}
}

[Link](); // 222
[Link](window); // 'window'
var fun = [Link]; // take out function body
fun(); // 'window' - this refers to window
[Link](obj); // 222

3. call / apply

function test() {
[Link](this);
}
test(); // window
[Link]({name: 'deng'}); // {name: 'deng'} - similar to test() but we can specify 'this' value
/*
[Link]({name: 'deng'}) --> AO {
arguments : {},
this: {name: 'deng'}, // changing this value
}
*/

4. global this --> window

call / apply and borrowing


use other functions to achieve own functionality
function Person(name, age) {
[Link] = name;
[Link] = age;
}

function Student(name, age, sex) {


// var this = [Link]([Link]);
[Link](this);
[Link] = sex;
}

Closure
nested function and an inner function is returned -> forming closure.
inner function returns to outside and hold the execution context of its outer function.

var obj = {};


function a() {
function b() {

}
[Link] = b; // store b outside of the function - forming a closure
}
a();

new and constructor function


construction of object = new + fn

three internal step inside the constructor function:

1. var this = {}
2. [Link] = xxx
3. return this

Note: function and constructor function both go through precompilation/ memory creation phase.
// regular function
function test() {
[Link]('test');
}

// constructor function
function Person() {
// with new, three internal steps to create object/ instance.
// 1. var this = {}
// 2. [Link] = xxx;
[Link] = 'abc';
[Link] = 123;
// 3. return this;
}

Person(); // without new, it is just like regular function, and this refers to window (global)
var person = new Person(); // with 'new', it creates object from the constructor function with t

Private Variable/ property


some variables we don't want people to access.

use closure.
function Person(name) {
// var this = {
// makeMoney: function() {},
// offer: function () {},
// }
var money = 100; // private variable
[Link] = name;
[Link] = function () {
money ++;
}
[Link] = function () {
money --;
}
}

var person = new Person('wx');


[Link]

// Example 2
var inherit = (function () {
var F = function () {}; // a intermediary - make it private is sensible
return function (Target, Origin) {
[Link] = [Link];
[Link] = new F();
}
});

/* Outcome: F is not accessible from outside, but it really exists.


var inherit = function (Target, Origin) {
[Link] = [Link];
[Link] = new F();
}
};
*/

// Example 3
function Person(name, age, sex) {
// var this = {}
var a = 0; // private variable
[Link] = name;
[Link] = age;
[Link] = sex;
function sss() {
a ++;
[Link](a);
}
[Link] = sss;
// return this
}

var oPerson = new Person();


[Link](); // 1
[Link](); // 2
var oPerson1 = new Person(); // rerun Person -> form new AO -> new closure
[Link](); // 1

Deep Copy
Issue with shallow copy: copy of reference type is only the reference to its memory location.

1. check reference type


2. check type of reference data type - e.g., [] or {}
3. if reference type, create a new empty reference type, copy individual item from the original one.

Exercise
Note: Any variable declared with var cannot be deleted from the global scope or from a function's
scope, because while they may be attached to the global object, they are not configurable.
// Exercise 1
// parameter x => var x
(function (x) {
delete x; // false - cannot be deleted as it is declared with var
return x;
})(1);

// 1

// Exercise 2
(function () {
return typeof arguments;
})(); // object

// Exercise 3
var h = function a() { // function name could be omitted as we can't access it outside.
return 23;
}
[Link](typeof a()); // TypeError: a is not a function
// Note: function name is useful when doing recursion inside function expression - it is accessi

// Exercise 3
function retDate(date) {
var arr = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
var ret = arr[date - 1];
if (ret === undefined) {
return 'error';
} else {
return ret;
}
}

Frontend
Junior: achieve functionalities.
Senior: optimise efficiency
Web achitect:

optimise the whole web efficiency


how to modularize and coordinate each developer efficiently.
efficiency, maintainability, coordination, discomposition.

You might also like