Professional JavaScript for Web Developers - Notes
# "Professional JavaScript for Web Developers" Notes
# Chapter 1: What Is JavaScript
JavaScript was born in 1995
A complete JavaScript consists of three parts:
- ECMAScript (core)
- DOM (Document Object Model)
- BOM (Browser Object Model)
ECMAScript host environments include:
- Browsers
- Node
- Flash
ECMAScript roughly defines the following components:
- Syntax
- Types
- Statements
- Keywords
- Reserved words
- Operators
- Objects
# Chapter 2: JavaScript in HTML
- The
<script>tag has the following common attributes:- async -- downloads the script immediately without blocking other page operations (asynchronous download)
- Cannot guarantee the order of each JS file
- Used for mutually independent JS files
- Main purpose is to avoid making the page wait for JS
- defer -- defers execution until the document is fully parsed and displayed
- Executes after the
</html>tag
- Executes after the
- src -- external file link
- type -- indicates the content type of the scripting language
text/javascript
- async -- downloads the script immediately without blocking other page operations (asynchronous download)
# Chapter 3: Language Basics
Syntax, borrowed from C
- Case-sensitive
- Identifiers refer to names of variables, functions, and properties
- The first character must be a letter, underscore, or dollar sign
- Other characters can be letters, underscores, dollar signs, or digits
Strict mode
"use strict"1Data types
- Primitive types
- Undefined, Null, Boolean, Number, String
- The
typeofoperator is generally used to check primitive types and returns the corresponding type as a string- "undefined", "boolean", "string", "number", "object", "function"
- Complex types
- Object
- Primitive types
Nulltype- Represents an empty object pointer
- If a variable is intended to hold an object but hasn't actually stored one yet, it should hold
null undefinedis derived fromnull, so comparing them with==returnstrue
Floating-point numbers are numbers that contain a decimal point with at least one digit after it
NaN
- Any operation involving NaN returns
NaN NaNis not equal to any value, includingNaNitself
- Any operation involving NaN returns
Number conversion
- There are 3 functions that convert non-numeric values to numbers
- Number() -- can be used with any data type
- parseInt() -- designed for converting strings to integers
- parseFloat() -- designed for converting strings to floating-point numbers
- There are 3 functions that convert non-numeric values to numbers
Strings
- Numbers, booleans, objects, and string values all have a toString() method for converting to strings
- undefined and null do not have a toString() method, but the String() method can be used
Object type
An object is essentially a collection of data and functionality
Creating an object using the Object() constructor
var obj = new Object(); // same as obj = {}1Every object instance has the following properties and methods
constructor-- points to the constructor used to create the current object. (In the example above, it'sObject())hasOwnProperty(propertyName)-- checks whether the given property exists on the current object instanceisPrototypeOf(Object)-- checks whether the passed-in object is the prototype of the current objectpropertyIsEnumerable(propertyName)-- checks whether the given property can be enumerated usingfor-intoLocaleString()-- returns the object's string representation, corresponding to the execution environment's localetoString()-- returns the object's string representationvalueOf()-- returns the object's string, numeric, or boolean representation. Usually the same astoString()
All objects have the properties and methods listed above
Operators
- Unary operators
- ++
- --
- The difference between prefix and postfix: when used with other numbers, prefix increments (decrements) first then operates with the other number, while postfix operates with the other number first then increments (decrements) itself
- Boolean operators
- AND (&&)
- Short-circuit operation: if the first operand can determine the result, the second operand is not evaluated
- OR (||)
- Short-circuit operation: if the first operand can determine the result, the second operand is not evaluated
- NOT (!)
- First converts to boolean using Boolean() then negates
- AND (&&)
- Unary operators
Statements (also called flow control statements)
if-else
do-while
Post-test loop statement: the code inside the loop body is executed at least once before the expression is evaluated
var i = 0 do { i += 2 } while (i < 10) // loops as long as i < 101
2
3
4
while
Pre-test statement
var i = 0 while (i < 10) { i += 2 } // loops as long as i < 101
2
3
4
for
Anything that can't be done with a while loop can't be done with a for loop either. A for loop simply collects all loop-related code in one place
for(initialization; condition; post-loop expression){ // ... }1
2
3break -- immediately exits the loop
continue -- exits the current iteration only
for-in -- used to enumerate an object's properties
Functions
- Any function can return any value at any time
- Functions without a specified return value return undefined
- Parameters are accessed through the arguments object, which is array-like
# Chapter 4: Variables, Scope, and Memory
Variables contain two types of values:
- Primitive type values -- simple data segments
- Reference type values -- objects that may consist of multiple values
Copying variable values
- Copying a primitive type variable value copies only a copy of the value itself
- When copying a reference type variable value, the value stored in the variable object is also copied to the new variable's space. However, this copy is actually a pointer that points to an object stored in the heap. Both variables point to the same object.
Passing parameters
- All function arguments are passed by value
Type detection
typeof-- detects primitive typesinstanceof-- detects reference types- variable instanceof Constructor (e.g., obj instanceof Object)
- All reference type values are instances of Object
Execution context
- In a browser, the global execution context is the
windowobject - Each function has its own execution context
- In a browser, the global execution context is the
Scope chain
- When code executes in an environment, a scope chain of variable objects is created
- At the front of the scope chain is always the variable object of the environment where the currently executing code resides.
- The next variable object in the scope chain comes from the containing (outer) environment, and the next from its containing environment. This continues all the way to the global execution context.
- The global execution context's variable object is always the last object in the scope chain.
Garbage collection
- JavaScript has an automatic garbage collection mechanism
- Variables that are no longer used are tagged, and tagged variables will be cleared during the collection cycle, freeing memory space.
- JavaScript has an automatic garbage collection mechanism
# Chapter 5: Reference Types
A reference type value is an instance of a reference type
A reference type is a data structure that describes the properties and methods that a class of objects possesses
There are two ways to create an Object instance:
var obj = new Object()1var obj = {} // same as new Object(), but doesn't actually call the Object constructor1
There are two ways to access object properties:
- Dot notation and bracket notation
# Array Type
The length property is not read-only
Detecting arrays
value instanceof Array1Array.isArray(value)1
Conversion methods
- toLocaleString() -- same as toString()
- toString() -- returns a string formed by the string representation of each value in the array, separated by commas
- valueOf() -- returns the array itself
# join() Conversion Method (does not modify the original array)
Accepts a single parameter -- a string to use as a separator, then returns a string containing all array items.
var arr = ['red','blue','green']
var arrStr = arr.join('|') // "red|blue|green"
arr.join() // "red,blue,green"
arr.join('') // "redbluegreen"
2
3
4
5
# Stack Methods, LIFO: push(), pop() (modifies the original array)
- push() -- adds items to the end of the array, returns the new length
- pop() -- removes the last item from the array, returns the removed item
# Queue Methods, FIFO: push(), shift(), unshift() (modifies the original array)
shift() -- removes the first item from the array, returns the removed item
unshift() -- adds items to the front of the array, returns the new length
push() and shift() form the queue methods
unshift() and pop() form the reverse queue methods
# Reorder Methods: reverse() and sort() (modifies the original array)
- reverse() -- reverses the order of array items
- sort() -- accepts a function as a parameter; the function receives two parameters.
- Custom sorting: inside the function, if the first parameter should come before the second, manually return a negative number; if the two parameters are equal, return 0; if the first parameter should come after the second, return a positive number.
// Ascending order
arr.sort(function(a,b){
if(a < b) {
return -1
} else if (a > b) {
return 1
} else {
retunr 0
}
})
2
3
4
5
6
7
8
9
10
Shorthand:
arr.sort((a,b) => {
return a-b // ascending; b-a for descending
})
2
3
# Manipulation Methods: concat(), slice(), splice()
concat() -- concatenates arrays (does not modify the original array)
var arr1 = ['a','b'] var arr2 = arr1.concat('c','d') // ['a','b','c','d']1
2slice() -- extracts a section (does not modify the original array)
- slice(start [, end]) -- returns items from the start position to the end position, not including the end position.
var arr1 = [1,2,3,4,5] var arr2 = arr1.slice(1,3) // [2,3] var arr3 = arr1.slice(2) // [3,4,5]1
2
3splice() -- splice/insert/delete (modifies the original array)
- splice(start, deleteCount, itemsToInsert)
- itemsToInsert can be zero or more items
- splice() always returns an array containing the deleted items from the original array. If nothing is deleted, it returns an empty array.
- The most powerful array method; can be used for deletion, insertion, and replacement
arr = [1,2,3,4] arr.splice(1,1) // [2] arr // [1,3,4] arr = [1,2,3,4] arr.splice(2,0,'a') // [] arr // [1,2,'a',3,4] arr = [1,2,3,4] arr.splice(3,1,'a') // [4] arr // [1,2,3,'a']1
2
3
4
5
6
7
8
9
10
11
12- splice(start, deleteCount, itemsToInsert)
# Position Methods: indexOf(), lastIndexOf()
- Find the position of an item; returns -1 if not found
- indexOf() searches from the beginning; lastIndexOf() searches from the end
# Iteration Methods: every(), some(), filter(), map(), forEach() (none modify the original array)
5 iteration methods, each accepting two parameters:
- A function to run on each item
- A scope object for running the function
The function receives three parameters:
- The item value
- The item index
- The array itself
every() -- returns true if the function returns true for every item
Example: check if every item in the array is greater than 2
var numbers = [1,2,3,2,1] var result = numbers.every((item,index,array) => { return item > 2 }) result // false1
2
3
4
5
some() -- returns true if the function returns true for any item
Example: check if the array contains a value greater than 2
var numbers = [1,2,3,2,1] var result = numbers.some((item,index,array) => { return item > 2 }) result // true1
2
3
4
5
filter() -- returns an array of items for which the function returns true
Example: filter out numbers less than or equal to 2
var numbers = [1,2,3,4,5] var result = numbers.filter((item,index,array) => { return item >2 }) result // [3,4,5]1
2
3
4
5
map() -- returns an array of the results of each function call
Example: multiply each item in the array by 2
var numbers = [1,2,3,4,5] var result = numbers.map((item,index,array) => { return item * 2 }) result // [2,4,6,8,10]1
2
3
4
5
forEach() -- iterates over each item in the array with no return value
Example: iterate over each item
var numbers = [1,2,3,4,5] numbers.forEach((item,index,array) => { // perform some operations })1
2
3
4
# Reduction Methods: reduce(), reduceRight()
reduce() -- reduces from left to right
reduceRight() -- reduces from right to left
Both methods iterate over all items in the array and build a final result that is returned
Each method accepts two parameters: a function to call on each item, and an initial value for the reduction
The function receives 4 parameters: the previous value, the current value, the current index, and the array object
Example: calculate the sum of all items in the array
var numbers = [1,2,3,4,5] var result = number.reduce((prev,cur,index,arr) => { return prev + cur }) result // 151
2
3
4
5For reduce(), on the first function call, prev is the first item and cur is the second item in the array
# Chapter 6: Object-Oriented Programming
# 6.1 Understanding Objects
- Definition of an object: an unordered collection of properties, where properties can contain primitive values, objects, or functions.
- A collection of key-value pairs, where values can be data or functions
# 6.1.1 Object Properties
Include two types: data properties and accessor properties
# 1. Data Properties
- configurable -- whether the property can be deleted or reconfigured (controls whether
deleteandObject.defineProperty()work), default true - enumerable -- whether the property is enumerable, default true
- writable -- whether the property can be written to, default true
- value -- the value, default undefined
Use Object.defineProperty() to modify these default attributes. Accepts three arguments: the object, the property name, and a descriptor object.
var person = {}
Object.defineProperty(person,'name',{
writable: false,
value: 'xu'
})
console.log(person.name) // xu
person.name = 'gao' // modification has no effect
console.log(person.name) // xu
2
3
4
5
6
7
8
9
When defining a property with this method without specifying configurable, enumerable, or writable, they default to false.
# 2. Accessor Properties
Contains two functions: a getter function and a setter function (both are optional). The getter is called when reading; the setter is called when writing.
Use Object.defineProperty() to define accessor properties.
var book = {
_year: 2020,
edition: 1
};
Object.defineProperty(book, 'year', {
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2020) {
this._year = newValue
this.edition += newValue - 2020
}
}
})
book.year = 2021
console.log(book.edition) // 2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
When only one of getter or setter is specified, the other cannot be used.
# 6.1.2 Defining Multiple Properties
Object.defineProperties() defines multiple properties. Accepts two parameters: the object to add or modify properties on, and a second object whose properties correspond one-to-one with properties of the first argument.
var book = {}
Object.defineProperties(book, {
_year: { // data property
writable: true,
value: 2004
},
edition: { // data property
writable: true,
value: 1
},
year: { // accessor property
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
}
})
// Three properties defined, each with a different descriptor
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 6.1.3 Reading Property Attributes (Descriptor Object)
Object.getOwnPropertyDescriptor() retrieves the descriptor. Accepts two parameters: the object the property belongs to, and the property name.
var book = {}
Object.defineProperties(book, {
_year: { // data property
writable: true,
value: 2004
},
edition: { // data property
writable: true,
value: 1
},
year: { // accessor property
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
}
})
var descriptor = Object.getOwnPropertyDescriptor(book, "_year")
console.log(descriptor) // {value: 2020, writable: true, enumerable: false, configurable: false}
var descriptor = Object.getOwnPropertyDescriptor(book, "year")
console.log(descriptor) // {enumerable: false, configurable: false, get: f, set: f}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 6.2 Creating Objects
Using the Object constructor or object literal syntax to create objects. Drawback: when creating many objects with the same interface, it produces a lot of repetitive code. Solution: use a variant of the factory pattern.