preface

This is the third time I’ve opened up the Little Red Book, JavaScript Advanced Programming 3rd Edition. I have to say, although the book has a few years and many knowledge points are not suitable for modern front-end development, but for front-end beginners who want to master the basics of JavaScript, Or if you’re like me and you want to retrieve those bits and pieces of knowledge that have been lost in the corner of your memory, this book is still perfect, and deserves to be called the “JavaScript Bible.”

This article is my reading notes. There is another reason why I choose to read this book again. I have made paper notes before, but THIS time I want to use it as an electronic version to sort out my previous knowledge

The length of this article is long, and it is intended to be my electronic study notes. I will try my best to remove the dross and take the essence. At the same time, I will add some important knowledge points not recorded in the book

let’s go

JavaScript introduction

A complete JavaScript consists of three parts, the core (ECMAScript syntax), the DOM, and the BOM. The latter two are now optional, or can be abstracted as hosts, since JS is no longer limited to browsers

Use JavaScript in HTML

SRC to point to a local JS file. SRC to point to a static server JS file (domain name). SRC is recommended. Caching improves page loading speed and DOM parsing speed compared to embedding, and is more maintainable because JS and HTML are decoupled

When the script tag is an external script in the form of SRC, you can set defer and async properties. The former enables the script to run after the page is parsed, while the latter asynchronously downloads and executes the script and asynchronously executes the JS code. These two attributes are designed to solve the problem of the browser having to wait for the JS code in the script tag to download and execute before parsing the following elements, resulting in a long blank screen

<script src="xxx" async></script>
Copy the code

Basic Concepts of JavaScript

identifier

Identifiers refer to the names of variables, functions, and attributes. The most common names are hump names, or $, _

The first character cannot be a number (but is legal from the second character on)

// illegal
let 123hello = '123'

// legitimate
let $123hello = '123'
let helloWorld = '123'
let hello123World = '123'
let _$hello = '123'
Copy the code

The data type

As of today,JavaScript has seven simple data types and one complex data type

Simple data types:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Symbol
  • BigInt (ES10 draft)

Complex data types:

  • Object

Function is a subclass of Object

Undefined type

Undefined has only one value, Undefined, and it’s very confusing with not defined, because they’re different and different

  • Using the Typeof operator returns ‘undefined’
  • Using undefined variables is safe; using variables not defined throws an error
let foo

console.log(typeof foo) // 'undefined'
console.log(typeof bar) // 'undefined'

console.log(foo) // undefined
console.log(bar) // Uncaught ReferenceError: bar is not defined
Copy the code

Null type

The Null type also has only one value, Null, which represents an empty object pointer. If typeof is used, the type returned is ‘object’, but this is a language BUG that is almost impossible to fix at the moment. If the instanceof operator is used to check whether it is an instanceof Object, it will return false

console.log(typeof null) // 'object'
console.log(null instanceof Object) // false
Copy the code

Undefined is derived from null, so they are loosely equal

console.log(undefined= =null) // true
Copy the code

The Number type

The JS Number type uses the IEEE754 format to represent integers and floating point values, which can cause minor problems, such as the JS 0.1 is not really 0.1, its binary is 0.001100110011… , an infinite loop (the rule for converting decimal to binary is to round by two), stored internally like this

The Number function converts the passed argument to the corresponding Number type (note the implicit conversion pit).

console.log(Number('123')) / / 123
console.log(Number(null)) / / 0
console.log(Number(undefined)) // NaN
console.log(Number('false')) // NaN
console.log(Number(true)) / / 1
Copy the code

NaN is of type Number, and NaN is not equal to itself. You can use the isNaN of the window object to determine whether the parameter isNaN. However, it has the disadvantage that it first converts the parameter to Number (again, implicitly). So isNaN(‘foo’) returns true, and ES6’s number. isNaN fixes this by returning false, proving that the string ‘foo’ is not a NaN

console.log(NaN= = =NaN) // false
console.log(isNaN(NaN)) // true
console.log(isNaN('foo')) // true But this is unreasonable because 'foo' is not a NaN
console.log(Number.isNaN('foo')) // false
Copy the code

Window. isNaN is used to determine whether the argument is a Number, and number. isNaN is used to determine whether the argument is a NaN

The difference between the parseInt and Number functions is that the former parses arguments character by character, while the latter converts them directly

console.log(parseInt('123.456')) / / 123
console.log(parseInt('123foo')) / / 123
console.log(Number('123foo')) // NaN
Copy the code

ParseInt parses the argument ‘123foo’ one by one, stops when it encounters a non-numeric character or decimal point (in this case string F), returns the previously converted Number, and Number converts the entire argument to a Number

(It is worth noting that parseFloat will return the converted number when it encounters a non-numeric character or the second decimal point.)

String

Strings in ECMAScript are immutable once they are created. If you need to change the string stored in a variable, you destroy the original string and populate the variable with a new value string

Object

DOM and BOM objects are host objects provided by the host, in this case the browser. In other words, non-browser environments may not have global variables and methods on the browser. For example, node does not have the alert method

The operator

Unary operator

Operators that operate on only one value are called unary operators. Postincrement/decrement operators differ from pre-increment/decrement in that postincrements are executed after the statements containing them have been evaluated

let num1 = 2
let num2 = 20
let num3 = --num1 + num2 / / 21
let num4 = num1 + num2 / / 21
Copy the code
let num1 = 2
let num2 = 20
let num3 = num1-- + num2 / / 22
let num4 = num1 + num2 / / 21
Copy the code

Num1 is num1 and num2 is num2 and num is num2 and num2 is num2 and num is num2 and num is num2 and num is num2 and num is num2 and num is num2 and num is num2

Boolean operator

Both the and and not operators are short-circuited, meaning that the second operand is not evaluated if the first operand determines the result

let num = 0
true || num++
console.log(num) / / 0
Copy the code

The following commonly used logic and judgment results

The first operand The operator Second operand The results of
null && any The first operand
undefined && any The first operand
NaN && any The first operand
false && any The first operand
“” && any The first operand
0 && any The first operand
object && any Second operand
true && any Second operand

If the first argument is false, the logic returns the first operand, or the second

Here is a list of all false values: false, null, undefined, 0, NaN, “”

Logic or the opposite of logic, the following commonly used logic or judgment results

The first operand The operator Second operand The results of
null || any Second operand
undefined || any Second operand
NaN || any Second operand
false || any Second operand
“” || any Second operand
0 || any Second operand
object || any The first operand
true || any The first operand

If the first argument is false, the logic returns either the second operand or the first

The additive operator

In ECMAScript, additive operators have some special behavior, which is broken down into strings and no strings in operands

All strings are treated as string concatenation. If one of them is a string and the other is not, it is converted to a string and then concatenated, and two situations occur

  • The second operand is an object, then [[toPrimitive]] is called to convert it to its original value, and string concatenation is still performed if the original value is a string
  • Operands that are not objects are treated as string concatenations
console.log("123" + 123) / / "123123"
console.log('123' + NaN) // "123NaN"
console.log("123" + {}) // "123[object Object]"
console.log("123" + undefined) // "123undefined"
Copy the code

If neither operand is a string, there are two more situations

  • If the operand is an object, [[toPrimitive]] is called to convert it to its original value, or string concatenation is performed if the original value is a string
  • If the operand is not an object, it is converted to Number and then evaluated

It’s worth noting that all four operations involving NaN end up with NaN (the other operand being a string is still considered string concatenation)

console.log(123 + true) / / 124
console.log(123 + undefined) // NaN is converted to NaN because of undefined
console.log(NaN + {}) // "NaN[object object]" contains objects that are converted to their original values, and are considered concatenated because they are strings
Copy the code

Relational operator

Like the additive operators, the relational operators (>, <, >=, <=) in JS can have some abnormal behavior

  • Perform a numeric comparison if both operands are numeric (always return false if either is NaN)
  • Both operands are strings, comparing the encoding values of strings one by one
  • If one of the operands is an object, the call [[toPrimitive]] is converted to the original value and compared as before
  • One of the operands is a Boolean, converted to Number, and then compared

For number two, let me give you an example

console.log('abc' < 'abd') // true
Copy the code

The string ABC is less than the string abd because the encoding of “c” is smaller than that of “d” (99 and 100)

Equality operator

The equality operator follows in the same lines as the additive and relational operators, and has a lot of strange characteristics that are still being criticized more than a decade later. Take a look at some examples on the web

undefined= =null //true[] [] = =//false[] = =! []//true{} = =! {}//false! [] = = {}//false[] = =! {}//true
[1.2] = =! [1] //false
Copy the code

I do not want to expand on the specific, good English friends can directly check the specification, I say personal memory skills

  • If the types are the same, the implicit conversion will occur only if the types are equal
  • When an object is involved, [[toPrimitive]] is called
  • NaN didn’t want to wait for anything, including himself
  • Both sides of the equation will be converted to Number as much as possible. If they are already of the same type on the way to Number, they will not be converted further
  • Null and undefined have some special behavior. First, they are loosely equal (==), but not strictly equal (===). Otherwise, no value is loosely or strictly equal to null/undefined

In general, to avoid implicitly converted pits, try to use strict equality (===)

For statement

The for statement is a derivative of the while statement. The for statement contains three expressions separated by semicolons. The first expression is usually a declaration or assignment statement, the second expression is a loop termination condition, and the third expression is executed after a loop

let i = 0

for(;; i++){/ /...
}
Copy the code

The above code into dead circulation, the browser crash, the reason is that the second expression is not set, will be seen as always is true, that will never be out of circulation, and each cycle variable I + 1, no initial statement at the same time, the code itself without any meaning, just shows three expressions of the for loop are optional

This is true if the for statements are sorted by the order in which they are executed

for (/ * 1 * /let i = 0;/ * 2 * /i < 10;/ * * / 3i++) {
    / * * / 4 console.log(i)
} 
Copy the code

The order is 1 -> 2 -> 4 -> 3 -> 4 -> 3 -> 4 -> 4 ->… – > exit

The for in statement

The for in statement returns the attributes of the Object and returns the order may be varied from the browser, because there is no specification, so don’t rely on it to return to the order, and Reflect. OwnKeys, Object. GetOwnPropertyNames, Object. GetOwnPropertySymbols is defined by the [[OwnPropertyKeys]] ES6 specification algorithm, its content is as follows

  • First return the integer properties sequentially (array properties)
  • Returns string properties in the order they were created
  • Finally, all symbolic properties are returned

Label statement

Use the label statement to add labels to the for statement. When the for statement exits internally with a break or continue statement, you can specify additional label names to exit to the outer loop, which is used in multi-level for loops

let num = 0

outer: for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        if (i === 5 && j === 5) {
            continue outer
        }
        num++
    }
}

console.log(num) / / 95
Copy the code

When I and j are both 5,5 traversals are skipped (55,56,57,58,59) and the final result is 95, or the loop has been executed 95 times

A switch statement

In switch statements, conditional penetration occurs if no break is written for each condition to exit the judgment

let i = 25

switch (i) {
    case 25:
        console.log('25')
    case 35:
        console.log('35')
        break;
    default:
        console.log('default')}/ / "25"
35 "/ /"
Copy the code

I satisfies the first case, so the string 25 is printed. However, since there is no break, the statement of the second case will be directly executed regardless of the second judgment condition. If there is no break in the second judgment condition, it will continue to penetrate into default

In the switch statement, cases are judged by strict equality. The string 10 does not equal the number 10

function

Prior to ES6, arguments to a function were stored in an object called Arguments and created at function execution time. It was an array of classes with the length property representing the number of arguments. The number of arguments in this case was the number of arguments passed to the function execution, not the number of arguments defined by the function

function func(a,b,c) {
    console.log(arguments)
}

func(1.2) // Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]
Copy the code

Arguments only reflect the number of arguments to a function at run time, and arguments also have some special features. In non-strict mode, arguments are linked to the number of arguments to a function at run time, and vice versa

function func(a,b,c) {
    console.log(arguments)
    a = 123
    console.log(arguments)
}

func(1.2) 
// Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]
// Arguments(2) [123, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ, length:2]
Copy the code
function func(a,b,c) {
    console.log(a)
    arguments[0] = 123
    console.log(a)
}

func(1.2) 
/ / 1
/ / 123
Copy the code

Strict mode does not make this kind of link, the two are completely separate, while ES6 can still use arguments, it is deprecated, and the remaining operators (…) are recommended.

Arguments to a function are passed by value, not by reference. That is, if the argument is an object, modifying the object with a parameter inside the function is reflected in all variables that refer to the parameter

let obj = {}

function func(o) {
    o.a = '123'
}

console.log(obj) / / {}
func(obj)
console.log(obj) // {a:"123"}
Copy the code

In func, we add the a attribute to the object via the parameter o, which is reflected in the variable obj

To be continued

The resources

JavaScript Advanced Programming 3rd Edition

JavaScript You Don’t Know

ECMA-262

MDN