JavaScript Programming Concepts Guide
JavaScript Programming Concepts Guide
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:
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 variable.
let name;
name = 'wx';
const: declares block-scoped local variables in which the value is a constant and reassignment is not
allowed.
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>
var org = {
department1: {jicheng : {
name: 'abc',
age: 123,
}, xuming : {}},
department2: {zhangsan : {}, lisi : {}},
}
[Link]([Link]);
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.
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.
Compared by values.
const a = 1;
const b = 1;
[Link](a === b); // true
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.
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](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
function
// read
[Link](arr[0]);
// write
arr[1] = 'changed';
// enumerate an array
// 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.
1. number
2. string
3. boolean
4. undefined
5. object
6. function
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
// Example 11
typeof null; // 'object' - special case due to historical bug.
typeof {}; // 'object'
typeof []; // 'object'
typeof ''; // 'string'
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
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).
able to retrieve numeral part from a string (truncate numbers) e.g., '123abc' => 123
[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
// 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)
[Link](parseFloat('100.2abcd')); // 100.2
[Link](parseFloat('[Link]')); // 123
4. String(mix)
[Link](String(null)); // 'null'
[Link](String(123.23)); // '123.23'
[Link](String(true)); // 'true'
5. Boolean(mix)
[Link](Boolean(123)); // true
[Link](Boolean('abc')); // true
[Link](Boolean(null)); // false
[Link](Boolean(undefined)); // false
[Link](Boolean("")); // false
6. toString(radix)
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
2. Increment/ Decrement ++ --
let a = "123";
a ++; // 123
let b = "abc";
b ++; // NaN - Number('abc') -> NaN - note: NaN itself is number type.
let a = +"abc";
[Link](a + " : " + typeof(a)); // NaN : 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. - * / %
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
[Link](b); // true
[Link](c); // false
[Link](c); // false
[Link](typeof a) // boolean
let b = 1 == "2"; //false - convert convert the string to a number. Conversion failure results i
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.
/* when one side is undefined or null, the other side is one of undefined or null, return false
// Number(null) => 0
undefined == 0; // false
null == 0; // false - note in equality null is not converted to number and thus it is false. //
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
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
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
var a = 123;
var b = 234;
var c = a;
a = b;
b = c;
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
consider types
no conversion
!= : Inequality
similar to equality
Comparison of Strings
ASCII
Rules:
2. compare the first character first, if similar, move on to the next and compare.
Comparison of 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.
rule:
let f = 1 + 1 && 1 - 1; // 0
// short-circuit evaluation
2 > 1 && [Link]('a'); // a
let a = 1;
let b = function () {
[Link]('[Link] is executed');
return 123;
}
|| OR
OR evaluates operands from left to right, returning immediately with the value of the first truthy
operand it encounters.
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
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).
Comma Operators
evaluates each of its operands (from left to right) and returns the value of the last operand.
// 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
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.
} 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 (score) {
[Link](score);
}
// Note: 90 < score < 100 => true < 100 (Please not write like this)
if (1 > 2) {
[Link]('hello');
}
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.
switch (n) {
case 'abc':
[Link]('a');
case 2: // match this
[Link]('b'); // run
case true:
[Link]('c'); // run
}
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.
// 1. let i = 0;
// 2. check i < 0; and run code
// 3. i++
// repeat
let 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 (condition)
statement
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.
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.
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()
}
function test() {
let a = 123;
let b = 234;
let c = a + b;
[Link](c);
}
Function Definition
Function Declaration
// function declaration
function fnName(param) {
// function body
}
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.
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.
function b() {
// 10000 lines
}
// IIFE
(function (){
var a = 123;
var b = 234;
[Link](a + b);
}())
Only expression can be used with function invocation operator xxx(). -> function name is abandoned/
ignored after the expression is executed.
1. function declaration
2. function expression.
// Calling function the normal way
function test() {
var a = 123;
[Link](a);
}
}()
- function test() {
[Link]('b');
}(); // b
0 || function test() {
[Link]('e');
}(); // e
// 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.
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)
// 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);
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.
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);
}
function add(a, b) {
let c = a + b;
[Link](c);
}
// passing argument
add(1, 2);
add(3, 2);
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
sum (11, undefined, 3, 'abc'); // note: as js doesn't specify data type, we can pass what we wan
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
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
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
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));
function fibonacci(n) {
if (n === 1) {
return 0;
}
if (n === 2) {
return 1;
}
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]);
}
*/
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.
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();
//
function test() {
let a = 123; // demo can't access
}
function demo() {
let b = 234; // test can't access
}
JavaScript Engine Overview
js
1. Parsing
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
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.
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;
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.
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.
test()
[Link](a); // undefined - a is local-scope variable.
[Link](b); // 123
Precompilation in Function Scope
AO {
a: 1, // a set to argument
b: undefined,
}
Note:
function fn(a) {
[Link](a); // 123
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);
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;
}
// 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
}
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
// 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]]
This hidden [[scope]] is a property of the function, created at declaration, not invocation.
Execution Context
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.
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.
Look for variable in scope chain, where contain AO and parent Variable Object (GO / AO). **
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.
Activation Objects
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();
}
/* 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();
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?
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`.
// 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();
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;
}
// Example 5
function test() {
var temp = 100;
function a() {
[Link](temp);
}
return a;
}
var demo = test();
demo(); // 100
Closure Usage
function count() {
count ++;
[Link](count);
}
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;
}
// 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
function callName() {
[Link](name);
}
return function () {
callName();
}
}())
init(); // abc
initDeng(); // 123
Objects
store various keyed collections and more complex entities.
[Link]();
[Link]([Link]);
[Link]();
[Link]([Link]);
Both are equivalent. But with different use case. Note that dot notation has certain case it can't deal
with.
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;
}
}
1. Object Literal
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();
[Link] = 'abc';
[Link] = 'female';
[Link] = function () {
[Link]('Hello');
}
3. [Link](proto, propertiesObject);
create objects with a designated prototype and also some properties.
// Example 2
[Link] = 'sunny';
function Person() {}
var person = [Link]([Link]);
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,}
}
// Example 2
// Example 3 - model how the mechanism work. - just for modelling, don't do this.
// String
// Boolean
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
// Example 5
var a = 5;
function test() {
a = 0;
alert(a);
alert(this.a);
var a;
alert(a);
}
// Example 6
function employee(name, code) {
[Link] = 'wangli';
[Link] = 'A001';
}
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.
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';
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;
}
// 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]?
function Car() {
[Link] = 'BMW';
}
[Link]([Link]);
/*ƒ Car() {
[Link] = 'BMW';
}*/
[Link]([Link]); // {}
[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.
[Link](person); // Person {}
// Old, deprecated way.
[Link](person.__proto__);
// modern way
[Link]([Link](person));
function Person() {
// this = {
// __proto__: [Link]
//}
}
var obj = {
name : 'sunny',
}
/* Simple illustration
var obj = {name: 'a'};
var obj1 = obj;
obj = {name: 'b'};
[Link] = {name:'a'};
__proro__ = [Link];
[Link] = {name: 'b'};
*/
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() {}
[Link] = grand;
function Father() {
[Link] = 'xuming';
}
[Link] = father;
function Son () {
[Link] = 'smoke';
}
var son = new Son();
[Link]([Link]); // ƒ toString() { [native code] }
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',
}
}
[Link] = father;
function Son() {
[Link] = 'smoke';
}
// Example 2 **
function Father() {
[Link] = 'xuming',
[Link] = {
card1: 'visa',
}
}
[Link] = father;
function Son() {
[Link] = 'smoke';
}
[Link].card1 = 'changed';
[Link]([Link].card1); // changed
// Example
function Father() {
[Link] = 100;
}
[Link] = father;
function Son() {
[Link] = 'smoke';
}
[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';
}
// Example 3
[Link] = {
height : 100,
}
function Person () {
[Link] = function () {
[Link] ++;
}
}
// Example 4
[Link] = 100;
function Fish() {}
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
[Link](); // SyntaxError: Invalid or unexpected token - as system think after dot (.) must
Both replace/ specify the value of this inside a function / constructor function with whatever value we
want.
One Difference:
Call
Call() method of a Fn calls this Fn with a given this value and arguments provided individually
use:
borrow constructor function for encapsulation of thisArg - bundling properties and methods of that
constructor function.
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;
}
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;
}
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
[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
call / apply
run the consturctor function implicitly run more than one function in a run.
3. Shared Prototype **
[Link] = [Link]
function Son() {}
[Link] = [Link];
// 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].
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. *****
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
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;
}
}
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.
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];
// Enumeration of Object
var obj = {
name: '13',
age: 123,
sex: 'male',
height: 180,
weight: 75,
}
/*
name string
age string
sex string
height string
weight string
*/
// Example
var obj1 = {
a: 123,
b: 234,
c: 345,
}
var prop;
for (prop in obj2) {
[Link]; // undefined - implicitly convert [Link] --> obj2['prop'], and obj2 doesn't have
}
var prop;
for (prop in obj2) {
[Link]; // 123 - implicitly convert [Link] --> obj2['prop'] thus accessing obj2's prop p
}
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',
}
}
}
}
// 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
*/
const obj = {
a : 1,
b : 2,
}
obj.c = 3; // allow
/*
1
2
3
*/
const obj = {
a : 1,
b : 2,
}
/*
1
2
*/
const obj = {
a : 1,
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
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,
}
}
3. instanceof : see if the prototype property of a constructor appears anywhere in the prototype
chain of an object
object instanceof Fn
use:
// object instanceof ConstructorFunction
// Example 1
function Person() {}
[Link](obj instanceof Person); // false - obj has no [Link] in its prototype chai
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
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() {}
}
4. When invoking a method using [Link]() , this keyword within the method refers to the
object itself
var obj = {
a: function () {[Link]('hi')},
}
// 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'],
}
clone(obj, obj1);
[Link] = 'wx';
[Link]([Link]); // abc
[Link]([Link]); // wx
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,},
}
// enumeration
// 1. check if primitive
// 2. check if array or object
// 3. create corresponding array or object
// recursion
deepClone(obj, obj1);
Array
zero-indexed
Definition
two ways. There are technically the same.
// array literal
var arr = [];
// Example
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
//
2. pop: removes the last element from an array and returns that element. - parameter: None
[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
[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]
/*
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
*/
[Link](function (a, b) {
if(a > b) {
return 1;
} else {
return -1;
}
});
[Link](arr)// [10, 3, 3, 2, 1, 1]
[Link](function (a, b) {
return a - b;
});
[Link](function (a, b) {
return b - a;
});
[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;
});
[Link](function (a, b) {
return [Link] - [Link];
});
[Link](function (a, b) {
//...
});
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.
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.
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.
Array-like Object
an object that has indexed properties and a length property.
The array object observes the length property, and automatically syncs the length
Advantages:
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
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"length": 3,
"push": [Link],
"splice": [Link],
}
[Link](1);
[Link](2);
[Link](obj); // { '2': 1, '3': 2, length: 4, push: [Function: push] }
/*
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.
error is unexpected.
[Link](data);
Error Name
Note: A programmer spends 3 / 4 times debugging.
use strict
with strict mode, browser no longer support es3 non-standardized sytax and use the latest standard.
syntax: write 'use strict' at the top of the code or function body to enable ES5 standard.
1. global
2. local
usage:
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:
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
function test() {
"use strict";
[Link]([Link]); // error
}
test();
demo(); // not executed due to error in the previous line.
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,
}
function test() {
var age = 123;
var name = 'scope';
with (obj) {
[Link](name); // obj
[Link](age); // 234
}
}
}
}
with ([Link]) {
[Link](name); // abc
}
with ([Link]) {
[Link](name); // xiaodeng
}
"use strict";
var a = b = 3; // ReferenceError: b is not defined
4. this
// non-strict mode
function Test() {
[Link](this);
}
[Link]({}); // {}
// strict mode
"use strict";
function Test() {
[Link](this);
}
[Link]({}); // {}
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.
// ES3.0
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).
usage:
measure a programme's performance.
Scheduling a Call
part of window object => thus this inside refers to window.
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.
clearTimeout(timerId)
usage:
1. as a timer
Note: object is for locally use while JSON is for data transfer.
XML
similar to HTML, but can customize tag.
<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,
}
var obj = {
name: 'wx',
age: 23,
}
2. [Link](str)
Revision
Wrapper
1. Primitive data type can't have properties or methods.
Prototype
[Link] = 'deng';
function Person() {
// var this = {
// __proto__: [Link]
//}
}
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
[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
[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
}
*/
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.
}
[Link] = b; // store b outside of the function - forming a closure
}
a();
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
use closure.
function Person(name) {
// var this = {
// makeMoney: function() {},
// offer: function () {},
// }
var money = 100; // private variable
[Link] = name;
[Link] = function () {
money ++;
}
[Link] = function () {
money --;
}
}
// Example 2
var inherit = (function () {
var F = function () {}; // a intermediary - make it private is sensible
return 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
}
Deep Copy
Issue with shallow copy: copy of reference type is only the reference to its memory location.
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: