Summary of JavaScript basic knowledge

1. Introduction of JavaScript

  • JavaScript was originally designed as a language for browsers, but is now used in many other environments as well.
  • JavaScript is now the most widely used browser language that is fully integrated with HTML/CSS.
  • There are many other languages that can be “compiled” into JavaScript, and these languages offer much more functionality. It is recommended that you learn some of these languages, at least in general, once you have mastered JavaScript.

2. The variable

We can use var, let, or const to declare variables to store data.

  • Let – the modern way of declaring variables.
  • Var – The old way of declaring variables. In general, we don’t use it anymore. However, we’ll cover the subtle differences between var and let in the old “var” section, just in case you need them.
  • Const – Similar to let, but the value of a variable cannot be modified.

Variables should be named in a way that makes it easy to understand what’s inside them.

3. Data types

There are eight basic data types in JavaScript.

  • Number is used for any type of number: integer or floating point, integer in the range ±(253-1).
  • Bigint is used for integers of arbitrary length.
  • String is for strings: A string can contain zero or more characters, so there is no separate single-character type.
  • Boolean is used for true and false.
  • Null is used for unknown values — a single type with only one NULL value.
  • Undefined for undefined values — a separate type with only one undefined value.
  • Symbol is used for unique identifiers.
  • Object is used for more complex data structures.

The Typeof operator allows us to view data types stored in variables.

  • Two forms: typeof X or typeof(x).
  • Return the type name as a string, such as “string”.
  • Typeof NULL returns “object” — an error in the JavaScript programming language that is not actually an object.

4. Type conversion

There are three common conversions: to string, to number, and to Boolean.

String conversions — Conversions occur when output content, and can also be explicitly converted via String(value). String conversions of primitive values are usually obvious.

Numeric conversions — Conversions occur when arithmetic operations are performed, and can also be explicitly converted by Number(value).

Digital conversions follow these rules:

Boolean conversions follow the following rules: Boolean conversions — Conversions occur when logical operations are performed. Explicit conversions can also be performed through Boolean(value).

When the numeric conversion to undefined is performed, the output is NaN instead of 0. Most of the rules above are easy to understand and remember. Here are some notable examples of how people usually make mistakes:

  • Boolean conversions to “0” and whitespace only strings such as “” output true.

5. Comparison of values

  • The comparison operator always returns a Boolean value.
  • Strings are compared, character by character, in dictionary order.
  • When different types of values are compared, they are converted to numbers (excluding strict equality checks) before being compared.
  • Under non-strict equality ==, null and undefined are equal and not equal to any other value.
  • When using > or < for comparison, note that the variable may be null/undefined. A better method is to separately check whether the variable is equal to null/undefined.

! And!!!!! The difference and usage of

  • ! Variables can be converted to Boolean type, null, undefined, and empty string are true, the rest are false.
! null=true ! undefined=true ! ''=true ! 100=false ! 'abc'=falseCopy the code
  • !!!!! Often used to make type judgments, in the first step! (variable) and then do the logical inverse operation.

For the following code:

If a is a non-empty, undefined, or non-empty string, execute the contents of the method body. if(a! =null&&typeof(a)! =undefined&&a! =''){//a code is executed only when there is content}Copy the code

This can be simplified using the following code:

if(!! A){//a code that has content to execute... }Copy the code

Methods are executed only if a is a meaningful variable, otherwise null, undefined, and “empty string” will not execute the following code.

6. Null value merge operator ‘?? ‘

  • Null-value merge operator?? Provides an easy way to select the first “defined” value from a list.

It is used to assign default values to variables:

// Set height to 100 height = height?? 100;Copy the code
  • ?? The operator has a very low priority, only slightly higher than? And =, so consider adding parentheses when using it in expressions.
  • If there is no clear add parentheses, not with the | | or && used together.

Loops: while and for

We learned three cycles:

  • While — Conditions are checked before each iteration.
  • do.. While — Conditions are checked after each iteration.
  • for (;;) Conditions are checked before each iteration, and other Settings can be used.

While (true) is usually used to construct “infinite” loops. This loop, like any other loop, can be terminated with the break command.

If we don’t want to do anything in the current iteration and want to move on to the next iteration, we can use the continue directive.

Break /continue break Breaks the loop, continue breaks the loop. Break is the only way to break out of the nested loop to go outside.

8. Function

The function declaration is as follows:

function name(parameters, delimited, by, comma) {
  /* code */
}
Copy the code
  • Values passed as arguments to a function are copied to local variables of the function.
  • Functions can access external variables. But it only works from the inside out. Local variables inside a function are invisible to code outside the function.
  • Functions can return values. If no value is returned, undefined is returned.

To keep the code concise and easy to understand, it is recommended to use local variables and parameters in functions, rather than external variables.

A function that takes parameters, uses them, and returns results is easier to understand than one that doesn’t take parameters but modifies external variables as side effects.

Function name:

  • The function name should clearly describe what the function does. When we see a function call in our code, a good function name lets us know immediately what the function does and what it returns.
  • A function is an action, so function names are usually verbs.
  • There are many excellent prefixes for function names, such as create… And the show… , get… And check… And so on. Use them to hint at functions.

9. Function expressions

Var functionName = function(arg0, arg1, arg2) {Copy the code
  • Functions are values. They can be assigned, copied, or declared anywhere in the code.
  • If a function is declared as a separate statement in the main code flow, it is called a “function declaration.”
  • If the function is created as part of an expression, it is called a “function expression.”
  • The internal algorithm handles function declarations before executing code blocks. So function declarations are visible anywhere within the block of code in which they are declared.
  • Function expressions are created when the execution process arrives.

In most cases, when we need to declare a function, it is best to use a function declaration because the function is visible before it is declared. This gives us more flexibility in how our code is organized and generally makes our code more readable.

Therefore, function expressions should be used only when the function declaration is inappropriate for the corresponding task.

10. Arrow functions, basics

The arrow function is quite handy for a one-line function. There are two kinds of it:

  1. Without curly braces :(… Args) => expression – The right hand side is an expression: the function evaluates the expression and returns its result.
  2. Curly braces :(… Args) => {body} – Curly braces allow us to write multiple statements in a function, but we need to explicitly return something.

Object of 11.

Objects are associative arrays with some special properties.

They store attributes (key-value pairs), where:

  • The key of the property must be a string or symbol (usually a string).
  • Values can be of any type.

We can access attributes as follows:

  • Dot symbol: obj.property.
  • Square brackets obj[“property”], which allow the key to be retrieved from a variable, such as obj[varWithKey].

Other operations:

  • Delete property: delete obj.prop.
  • Check for the presence of a given key property: “key” in obj.
  • Traversal object: for(let key in obj) loop.

What we study in this chapter are called plain objects, or just objects.

There are many other types of objects in JavaScript:

  • Array is used to store ordered collections of data,
  • Date is used to store dates and times.
  • Error stores Error information.
  • … And so on.

They have their own special characteristics, as we will learn later. Sometimes people say “Array type” or “Date type”, but they are not their own types, but belong to an object type called “object”. They extend “object” in different ways.

12. Object reference and copy

Objects are assigned and copied by reference. In other words, a variable does not store the “value of the object”, but rather a “reference” (memory address) to the value. Therefore, when you copy such a variable or pass it as a function parameter, you copy the reference, not the object itself.

All operations that pass through copied references (such as adding or deleting attributes) apply to the same object.

To create a “true copy” (a clone), we can use object. assign to do so-called “shallow copies” (nested objects are copied by reference) or use “deep copy” functions such as _.clonedeep (obj).

13. Object method, “this”

  • Functions stored in object properties are called “methods.”
  • Method allows an object to do “operations” like object.dosomething ().
  • Method can refer to an object as this.
  • The value of this is obtained while the program is running.
  • A function may use this when it is declared, but this has a value only when the function is called.
  • You can copy functions between objects.
  • When calling a function with the syntax of “method” : object.method(), this value in the call is object.

Note that arrow functions have something special: they don’t have this. Any this accessed inside the arrow function is retrieved from the outside.

14. Optional chain? “” .”

Optional chain? There are three forms of grammar:

  1. obj? .prop — obj. Prop is returned if obj exists, undefined otherwise.
  2. obj? .[prop] — obj[prop] is returned if obj exists, undefined otherwise.
  3. obj.method? .() — call obj.method() if obj.method exists, otherwise return undefined.

As we can see, these grammatical forms are straightforward to use. ? . Check if the left part is null/undefined, if not, continue.

? .chains allow us to securely access nested properties.

However, we should use it carefully. . Use only when the left part is not present and is ok. To make sure that when there are programming errors in the code, they are not hidden from us.

15. The Symbol type

Symbol is the basic type of unique identifier

Symbol is created using a Symbol() call with an optional description (name).

Symbol always has different values, even if they have the same name. If we want symbols with the same name to be equal, then we should use the global registry: symbol.for (key) returns (if necessary creates) a global Symbol with key as its name. Using symbol. for to call the Symbol with the same key multiple times returns the same Symbol.

Symbol has two main usage scenarios:

  1. Hide object properties. If we want to add a property to an object that “belongs” to another script or library, we can create a Symbol and use it as the property’s key. The Symbol attribute does not appear in for.. In, so it is not accidentally handled with other attributes. Also, it will not be accessed directly because the other script does not have our Symbol. Therefore, the property is protected from accidental use or overwriting.

So we can use the Symbol attribute to “secretly” hide something in the object we want, but not see it anywhere else.

  1. JavaScript uses a number of system symbols that can be accessed as symbols.*. We can use them to change some of the built-in behaviors. For example, later in the tutorial, we will use symbol. iterator for iteration, symbol.toprimitive for conversion of the object’s original value, and so on.

Technically, Symbol is not 100% hidden. Have a built-in method Object. GetOwnPropertySymbols (obj) allows us to get all the Symbol. There is also a method called reflect.ownKeys (obj) that returns all the keys of an object, including symbols. So they’re not really hidden. But most libraries, built-in methods, and syntactic constructs do not use these methods.

16. Numeric types

Write numbers with lots of zeros:

  • Append the number “e” and “0” to the number. Like: 123e6 is the same as 123 followed by six zeros.
  • The negative number after “e” will divide the number by 1 followed by a given number of zeros. For example 123E-6 means 0.000123 (one millionth of 123).

For different number systems:

  • You can write numbers directly to hexadecimal (0x), octal (0O), and binary (0b) systems.
  • ParseInt (STR, base) parseInt(STR, base) parses the string STR as an integer in the given base number system, 2 ≤ base ≤ 36.
  • Num.tostring (base) converts a number to a string in the given base number system.

To convert values like 12pt and 100px to numbers:

  • A “soft” conversion uses parseInt/parseFloat, which reads a number from a string and returns a value that could have been read before an error occurred.

Decimal Numbers:

  • Round using math.floor, math.ceil, math.trunc, math.round, or num.tofixed (precision).
  • Be sure to remember that accuracy is lost when using decimals.

More mathematical functions:

  • Look at the Math object if necessary. The library is small, but meets basic requirements.

17. The string

  • There are three types of quotes. Backquotes allow strings to span multiple lines and can be used with ${… } embed an expression in a string.
  • Strings in JavaScript are encoded in UTF-16.
  • We can use special characters like \n or by using \u… To manipulate their Unicode for character insertion.
  • To get a character, use [].
  • Get substrings, using slice or subString.
  • To convert a string toLowerCase, use toLowerCase/toUpperCase.
  • Search string, use the indexOf or includes/startsWith/endsWith simple checks.
  • Use localeCompare when comparing strings by language; otherwise, compare by character code.

There are several other useful string methods:

  • Str.trim () — Removes Spaces before and after strings (” trims “).
  • Str.repeat (n) — Repeat the string n times.
  • … Please refer to the manual for more details.

An array of 18.

Arrays are special objects for storing and managing ordered items of data.

  • Statement:

    Let arr = [item1, item2…] ;

    Let arr = new Array(item1, item2…) ;

Calling new Array(number) creates an Array of a given length without any entries.

  • The length attribute is the length of the array. Specifically, it is the last numeric index value of the array plus one. It is automatically tuned by array methods.
  • If we manually shorten the length, the array will be truncated.

We can use arrays as double-ended queues by:

  • push(… Items) adds the items item to the end.
  • Pop () removes the element from the end and returns it.
  • Shift () removes the element from the header and returns it.
  • unshift(… Items) adds items from the header.

Iterate over the elements of the array:

  • for (let i=0; i
  • For (let item of ARR) – Modern syntax, only items can be accessed.
  • For (let I in arr) — Never use this.

When comparing arrays, don’t use the == operator (and certainly don’t use operators like > and <), because they don’t do anything special to arrays. They typically treat arrays like any object, which is usually not what we want.

However, we can use for.. The of loop compares arrays item by item.

19. Array methods

Array methods cheat sheet:

  • Add/Remove elements:

    • push(… Items) — add elements to the end,
    • Pop () — extract an element from the end,
    • Shift () — Extract an element from the beginning,
    • unshift(… Items) — add elements to the header,
    • splice(pos, deleteCount, … Items) — Delete deleteCount elements from pos and insert items.
    • Slice (start, end) — Creates a new array that copies elements from index start to index end (but not end).
    • concat(… Items) — Returns a new array by copying all the elements of the current array and adding items to it. If any of the items is an array, then its elements are taken.
  • Search elements:

    • IndexOf /lastIndexOf(item, pos) — search for an item starting from the index pos, return the indexOf that item if found, otherwise -1.
    • Includes (value) – Returns true if the array has value, false otherwise.
    • Find /filter(func) — Filters elements through func and returns the first value/all values that make func return true.
    • FindIndex is similar to find, but returns an index instead of a value.
  • Traversal elements:

    • ForEach (func) — calls func on each element, returning nothing.
  • Conversion array:

    • Map (func) – Creates a new array based on the result of calling func on each element.
    • Sort (func) — Sort the array in-place and return it.
    • Reverse () — Reverses the array in place and returns it.
    • Split /join — converts string to array and returns.
    • Reduce /reduceRight(func, Initial) — Calculate individual values on the array by calling func on each element and pass intermediate results between calls.
  • Other:

    • Array.isArray(arr) Checks if arR is an Array.

Note that the sort, reverse, and splice methods modify the array itself.

These are the most common methods, covering 99% of use cases. But there are a few others:

  • Arr.some (fn)/arr.every(fn) checks arrays.

Similar to map, the function fn is called for each element of the array. Return true if any/all of the results are true, false otherwise.

The behavior of these two methods are similar to | | and && operator: if fn returns a true value, arr. Some () returns true immediately and stop the iteration the rest of the array; If fn returns a false value, arr.every() immediately returns false and stops iterating over the remaining array items.

We can use every to compare arrays:

function arraysEqual(arr1, arr2) {
  return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]);
}

alert( arraysEqual([1, 2], [1, 2])); // true
Copy the code
  • Arr.fill (value, start, end) — From index start to end, fills the array with repeated values.
  • Arr.copywithin (target, start, end) — Copies all elements from position start to end to its target location (overwriting existing elements).
  • Arr.flat (depth)/arr.flatMap(fn) creates a new flat array from a multidimensional array.
  • Array.of(element0[, element1[,… [, elementN]]) creates a new Array instance based on a variable number of parameters, regardless of the number or type of parameters.

See the manual for a complete list.

An Iterable object is an Iterable object.

You can use for.. Objects of of are said to be iterable.

  • Technically, iterables must implement the symbol. iterator method.

    • The result of an objsymbol. iterator is called an iterator. It handles further iterations.
    • An iterator must have a next() method, which returns a {done: Boolean, value: any} object, where done:true indicates the end of the iteration, otherwise value is the next value.
  • The Symbol. Iterator method is called for.. Of is called automatically, but we can also call it directly.

  • Built-in iterables such as strings and arrays implement symbol. iterator.

  • String iterators recognize surrogate pairs. (Proxy pairs are utF-16 extensions.)

Objects with indexed and length attributes are called array-like objects. Such objects may have other properties and methods, but no built-in methods for arrays.

If we take a closer look at the specification — most of the built-in methods assume that they need to deal with iterable or array-like objects, not “real” arrays, because that’s more abstract.

Array.from(obj[, mapFn, thisArg]) converts the iterable or array-like object obj to a real Array Array, and then we can apply Array methods to it. The optional arguments mapFn and thisArg allow us to apply the function to each element.

21. Map and Set

Map – is a collection of data items with keys.

Methods and attributes are as follows:

  • New Map([iterable]) — Create a Map and select an iterable (such as an array) with [key,value] pairs to initialize.
  • Map.set (key, value) – Stores values by key.
  • Map.get (key) — Returns the value by key, or undefined if no key exists in the map.
  • Map.has (key) – Returns true if key exists, false otherwise.
  • Map.delete (key) — Deletes the value of the specified key.
  • Map.clear () — Clears the map.
  • Map. size – Returns the current number of elements.

Differences with common Object:

  • Any key or object can be a key.
  • There are other handy methods, such as the size attribute.

Set – is a Set of unique values.

Methods and properties:

  • New Set([iterable]) — Creates a Set, optionally initialized with an iterable (such as an array).
  • Set.add (value) — Adds a value (without modifying it if it exists) and returns the set itself.
  • Set.delete (value) — Deletes the value, returning true if it exists at the time of the method call, false otherwise.
  • Set.has (value) – Returns true if value is in set, false otherwise.
  • Set.clear () — Clears the set.
  • Set.size – Number of elements

In maps and sets, iteration is always done in the order in which values are inserted, so we can’t say that collections are unordered, but we can’t reorder elements or get them by their numbers.

WeakMap and WeakSet (WeakMap and WeakSet)

WeakMap is a map-like collection that only allows objects as keys and removes them along with their associated values if they are not otherwise accessible.

A WeakSet is a set-like collection that stores only objects and removes them if they are not otherwise accessible.

None of them supports methods and attributes that reference all keys or their counts. Only one operation is allowed.

WeakMap and WeakSet are used as “secondary” data structures in addition to the “primary” object store. Once an object is removed from main storage, it is automatically cleared if the object is only used as a key for a WeakMap or a WeakSet.

23. Deconstruct assignment

  • Destruct assignment instantly maps an object or array to multiple variables.

  • The full syntax for deconstructing objects:

    let {prop : varName = default, … rest} = object

This means that the property prop will be assigned to the variable varName, or the default value default will be used if the property is not present.

Object properties that have no corresponding mapping are copied to REST objects.

  • Full syntax for deconstructing arrays:

    let [item1 = default, item2, …rest] = array

The first element of the array is assigned to Item1, the second element is assigned to Item2, and all remaining elements are copied to another array, REST.

  • It is also possible to extract data from nested arrays/objects, in which case the left-hand side of the equals sign must have the same structure as the right-hand side.

24. Date and time

  • In JavaScript, dates and times are represented using Date objects. We can’t just create dates, or just times; the Date object always creates both.
  • Months are counted from 0 (yes, January is 0).
  • GetDay () for a day of the week also starts at 0 (0 is Sunday).
  • Date self-calibrates when a component is set out of scope. This is useful for adding and subtracting days/months/hours.
  • Dates can be subtracted to get the difference in milliseconds. Because when a Date is converted to a number, the Date object is converted to a timestamp.
  • Date.now() is a faster way to get a timestamp for the current time.

Unlike other systems, timestamps in JavaScript are measured in milliseconds, not seconds.

Sometimes we need a more precise measure of time. JavaScript itself does not have a method for measuring microseconds (millionths of a second), but most runtime environments do. For example, the browser has the perform.now () method to give the number of microseconds in milliseconds (to three decimal places in milliseconds) since the page loaded:

alert(`Loading started ${performance.now()}ms ago`); // This is similar to "Loading started 34731.26000000001ms ago" //.26 indicates microseconds (260 microseconds) // More than 3 decimal places are precision errors, only the first three digits are correctCopy the code

Node.js has the microtime module and other methods. Technically, almost all devices and environments allow you to get higher precision values, just not through Date objects.

25. JSON method, toJSON

  • JSON is a data format with its own independent standards and libraries for most programming languages.
  • JSON Supports object, array, String, Number, Boolean, and NULL.
  • JavaScript provides a method to serialize to JSON, json.stringify, and a method to parse JSON, json.parse.
  • Both methods support conversion functions for intelligent read/write.
  • If an object has toJSON, it will be called json.stringify.

26. Recursion and stack

Terms:

  • Recursion is the programming term for calling a function from itself. Recursive functions can be used to solve problems in a more elegant way.

When a function calls itself, we call it a recursive step. The basis of recursion is that function arguments make the task so simple that the function does not need to be called further.

  • A recursively defined data structure is a data structure that can be defined by itself.

For example, a linked list can be defined as a data structure consisting of objects referencing a list (or NULL).

list = { value, next -> list }
Copy the code

HTML element trees, or the Department tree in this chapter, are also recursive in nature: they have branches, and branches can have other branches.

As we saw in the example sumSalary, you can iterate over them using recursive functions.

Any recursive function can be rewritten in iterative form. Sometimes this is what you need to do when optimizing your code. But for most tasks, recursive methods are fast enough and easy to write and maintain.

27. Rest parameters and Spread syntax

When we see “…” in code Is either a REST parameter or a spread syntax.

There’s an easy way to tell them apart:

  • If… Appearing at the end of the function argument list is the REST argument, which collects the remaining arguments from the argument list into an array.
  • If… If it appears in a function call or similar expression, it is the spread syntax, which expands an array into a list.

Usage Scenarios:

  • Rest arguments are used to create functions that can take any number of arguments.
  • Spread syntax is used for functions that pass arrays to lists that typically require many arguments.

Both of them help us easily switch back and forth between lists and parameter arrays.

The “old” arguments (array-like and iterable objects) also help us get all the arguments in a function call.

28. Global objects

  • Global objects contain variables that should be visible anywhere.
  • These include JavaScript built-in methods such as “Array” and environment-specific values such as window.innerheight — the height of the window in the browser.
  • The global object has a generic name globalThis.
  • … But it’s more common to use “old-fashioned” environment-specific names, such as Window (browser) and global (Node.js).
  • A value should be stored in a global object only if it is truly global to our project. And keep them to a minimum.
  • In browsers, global functions and variables declared using var become properties of global objects unless we use modules.
  • To make our code future-oriented and easier to understand, we should use direct access to properties of global objects, such as window.x.

Function object, NFE

A function is an object.

We have introduced some of their properties:

  • Name – The function name. It is usually taken from the function definition, but if the function name is not specified at the time of the function definition, JavaScript will try to guess a function name from the context of the function (for example, assigning the variable name to the function name).
  • Length – The number of input arguments to the function definition. Rest parameters do not participate in counting.

If a Function is declared as a Function Expression (not in the main code stream) with a name attached, it is called Named Function Expression. This name can be used to make self-calls within the function, such as recursive calls.

In addition, functions can have additional attributes. Many well-known JavaScript libraries take full advantage of this feature.

They create a “main” function and then attach many other “helper” functions to it. For example, the jQuery library creates a function called $. The LoDash library creates a _ function and adds.add,.keyby, and other attributes to it (see Docs for more). In fact, they do this to reduce pollution of the global space, so that a library has only one global variable. This reduces the likelihood of naming conflicts.

So, a function can do a useful job on its own, and it can have a lot of other functionality attached to its properties.

29. “new Function” syntax

Grammar:

let func = new Function ([arg1, arg2, ...argN], functionBody);
Copy the code

For historical reasons, arguments can also be given as comma delimiters.

The following three statements have the same meaning:

new Function('a', 'b', 'return a + b'); New Function('a,b', 'return a + b'); New Function('a, b', 'return a + b'); // Separate by commas and SpacesCopy the code

A Function created using new Function whose [[Environment]] points to the global lexical Environment, not the external lexical Environment of the Function. Therefore, we cannot use external variables directly in new Function. This is a good thing, though, because it helps reduce the chances that our code will fail. And, from a code architecture point of view, it is better to use parameter passing explicitly and avoid the problems of using compressors.

30. Scheduling: setTimeout and setInterval

  • setTimeout(func, delay, … Args) and setInterval(func, delay… The args method allows us to run func once after delay milliseconds or periodically at delay millisecond intervals.
  • To cancel the function of the execution, we should call clearInterval/clearTimeout, and will return to value as the setInterval/setTimeout into the incoming refs.
  • Nested setTimeout is more flexible than setInterval, allowing us to set the time between executions more precisely.
  • Zero delay scheduling setTimeout(func, 0) (the same as setTimeout(func)) is used to schedule calls that need to be executed as soon as possible, but will be called after the current script has finished executing.
  • Browsers limit the minimum delay of five or more nested calls (after five calls) for setTimeout or setInterval to 4ms. This is a problem left over from history.

Note that none of the scheduling methods can guarantee an exact delay.

For example, timers in the browser can be slow for a number of reasons:

  • The CPU overload.
  • The browser TAB is in background mode.
  • Laptops run on battery power.

All of these factors can increase the timer’s minimum timer resolution (minimum latency) to 300ms or even 1000ms, depending on the browser and its Settings.

31. Decorator patterns and forwarding, Call /apply

A decorator is a wrapper around changing the behavior of a function. The main work is still done by this function.

Decorators can be thought of as “features” or “aspects” that can be added to functions. We can add one or more. And all without changing its code!

To implement the cachingDecorator, we looked at the following methods:

  • Func. Call (context, arg1, arg2)… Call func with the given context and parameters.
  • Func. Apply (context, args) — Call func to pass the context as this and the args of the class array to the argument list.

Generic call forwarding is usually done using Apply:

let wrapper = function() {
  return original.apply(this, arguments);
};
Copy the code

We can also see an example of method borrowing, where we borrow a method from one object and “call” it in the context of another object. It is common to take array methods and apply them to arguments. The alternative is to use the Rest parameter object, which is a real array.

32. Function binding

Method func. Bind (context,… Args returns a “bound variant” of func that binds the context this and the first argument (if given).

Usually we apply bind to bind the this of the object method so that we can pass them to use elsewhere. For example, pass to setTimeout.

When we bind certain parameters of an existing function, the (less general) bound function is said to partially applied or partial.

Partial is useful when we don’t want to repeat the same parameters over and over again. Just like we have a send(from, to) function, and for our task, from should always be the same, we can do a partial and use it.

33. Understand arrow functions in depth

Arrow function:

  • There is no this
  • Without the arguments
  • You cannot call with new
  • They don’t have super either, but we haven’t learned that yet. We’ll learn about this in the class Inheritance chapter.

This is because arrow functions are for short code that has no “context” of its own, but works in the current context. And the arrow function really shines in this usage scenario.

34. Prototype inheritance

  • In JavaScript, all objects have a hidden [[Prototype]] property, which is either another object or null.
  • We can access it using obj. Proto (historical getters/setters, but there are other methods, which we’ll get to soon).
  • Objects referenced by [[Prototype]] are called “prototypes”.
  • If we want to read a property of obj or call a method, and it doesn’t exist, then JavaScript will try to find it in the prototype.
  • Write/delete operations are performed directly on the object, and they do not use stereotypes (assuming it is a data property, not a setter).
  • If we call obj.method() and method is retrieved from the prototype, this will still refer to obj. Therefore, a method is always used with the current object, even if the method is inherited.
  • for.. An in loop iterates over itself and inherited properties. All other key/value fetching methods work only on the object itself.

35. F.prototype

It’s all very simple, just need to remember a few key points to grasp clearly:

  • The f.protoType attribute (not to be confused with [[Prototype]]) assigns the new object’s [[Prototype]] value when new F is called.
  • The value of f.protoType is either an object or null: nothing else works.
  • The “prototype” attribute has this special effect only if a constructor function is set and called by new.

Prototype is nothing special on a regular object:

Let user = {name: "John", prototype: "bla-bla"};Copy the code

By default, all functions have f.constructor = {constructor: F}, so we can get an object’s constructor by accessing its “constructor” property.

36. Native prototypes

  • All built-in objects follow the same pattern:

    • Methods are stored in prototype (array. prototype, Object.prototype, date. prototype, etc.).
    • The object itself stores only data (array elements, object attributes, dates).
  • The primitive data type also stores the methods in the prototype of the wrapper object: number. prototype, String.prototype, and Boolea.prototype. Only undefined and NULL have no wrapper objects.

  • Built – in prototypes can be modified or populated in new ways. However, changing them is not recommended. The only time this is possible is when we add a new standard that is not yet supported by the JavaScript engine, but has been added to the JavaScript specification.

37. Prototype approach, noprotoThe object of

Modern ways to set up and directly access stereotypes are:

  • Object.create(Proto, [descriptors]) – Creates an empty Object using the given proto as [[Prototype]] (may be null) and optional attribute descriptions.
  • Object.getprototypeof (obj) — Returns the [[Prototype]] of the Object obj (same as the getter for Proto).
  • Object.setprototypeof (obj, proto) — Sets [[Prototype]] of Object obj to proto (same as setter for proTO).

If you want to put a user-generated key into an object, the built-in Proto getter/setter is not safe. Because the user might type “proto” as a key, this causes an error, which we hope isn’t a big deal, but often has unexpected consequences.

Therefore, we can use object.create (null) to create a “very plain” Object without proto, or stick with a Map Object for such scenarios.

In addition, Object.create provides a simple way to shallow copy all of an Object’s descriptors:

let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
Copy the code

In addition, we make it clear that Proto is the getter/setter for [[Prototype]], just like any other method, in Object.prototype.

We can create an Object without a prototype with Object.create(null). Such objects are used as “pure dictionaries,” for which there is no problem using “proto” as a key.

Other methods:

  • Keys (obj)/object.values (obj)/object.entries (obj) – Returns an enumerable array of its own string property names/values/key-value pairs.
  • Object. GetOwnPropertySymbols (obj) – returns a symbol of all types of themselves the keys of the array.
  • Object. GetOwnPropertyNames (obj) – returns an array composed of all the string keys by itself.
  • Reflect.ownkeys (obj) – Returns an array of all its keys.
  • Obj. HasOwnProperty (key) : Returns true if obj has its own (non-inherited) property named key.

All methods that return Object properties (such as object.keys and others) — return properties of themselves. If we want to inherit them, we can use for… The in.

38. Basic Class syntax

The basic class syntax looks like this:

class MyClass { prop = value; / / attribute constructor (...). {// constructor //... } method(...) {} // method get something(...) {} // Getter method set something(...) {} // setter method [symbol.iterator]() {} // There are methods to calculate (Symbol here) names //... }Copy the code

Technically, MyClass is a function (the one we provide as constructor), while methods, getters, and settors are all written to MyClass.prototype.

39. The class inheritance

  1. Want to extend a class: class Child extends Parent:
  • This means that child.prototype. proto will be Parent. Prototype, so the method will be inherited.
  1. Rewrite a constructor:
  • Before using this, we must call the parent constructor to super() in the Child’s constructor.
  1. Override a method:
  • We can call the Parent method with super.method() in a Child method.
  1. Internal:
  • Methods remember their class/object in the internal [[HomeObject]] property. That’s how super resolves the parent method.
  • Therefore, it is not safe to copy a method with super from one object to another.

Supplement:

  • Arrow functions don’t have their own this or super, so they blend into the nearest context as if they were transparent.

Static properties and static methods

Static methods are used to implement functionality that belongs to an entire class. It is independent of the specific class instance.

For example, a comparison method Article.compare(article1, article2) or a factory method article.createToDays ().

In class life, they are all marked with the keyword static.

Static properties are used when we want to store class-level data, rather than binding to instances.

The syntax is as follows:

class MyClass {
  static property = ...;

  static method() {
    ...
  }
}
Copy the code

Technically, a static declaration is the same as assigning a value directly to the class itself:

MyClass.property = ...
MyClass.method = ...
Copy the code

Static properties and methods are inheritable.

For class B extends A, the prototype of class B refers to A: B.[[prototype]] = A. Therefore, if A field is not found in B, the search continues in A.

41. Private and protected properties and methods

In the case of object-oriented programming (OOP), the division between internal and external interfaces is called encapsulation.

It has the following advantages:

Protect users so they don’t hurt themselves

Imagine a group of developers using a coffee maker. The coffeemaker, made by The company Best Coffeemaker, worked fine, but the protective cover was removed. So the internal interfaces are exposed.

All developers are civilized — they use the coffee machine as expected. But one of them, John, thought he was the smartest guy and made some adjustments to the inside of the coffee maker. However, the coffee machine broke down two days later.

It was certainly not John’s fault, but the fault of the man who removed the shield and let John operate.

The same goes for programming. If a user of a class wants to change something that was never intended to be changed externally — the consequences are unpredictable.

supportability

The programming situation is much more complicated than a real-life coffee machine, because we don’t just buy it once. We also need to constantly develop and improve the code.

If we strictly define the internal interface, the class’s developers are free to change their internal properties and methods without even notifying the users.

If you’re a class developer like this, you’ll be happy to know that you can safely rename private variables, change or even remove their arguments, because no external code depends on them.

For users, the interior of an application may be overhauled when a new version comes out, but it’s still easy to upgrade if the external interface is the same.

Hiding complexity

People like to use simple things. At least from the outside. What’s inside is a different story.

Programmers are no exception.

It is always convenient when implementation details are hidden and simple and documented external interfaces are provided.

To hide the internal interface, we use a protected or private property:

  • Protected fields start with _. This is a well-known convention and is not enforced at the language level. A programmer should only access fields starting with _ through its classes and classes inherited from it.
  • Private fields start with #. JavaScript ensures that we can only access classes from within.

Currently, private fields are not well supported by browsers, but can be addressed with Polyfill.

Class check: “instanceof”

Let’s summarize what we know about type checking:

The Instanceof operator works well in scenarios where we use hierarchy of a class and want to examine that class while also considering inheritance. As we can see, {}.toString is technically a “more advanced” Typeof.

43. A Mixin mode

Mixin – is a generic object-oriented programming term: a class that contains the methods of another class.

Some other programming languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototypes.

We can use mixins as a way to extend a class by adding a variety of behaviors, such as the event handling mentioned above.

Mixins can be a point of conflict if they accidentally override methods of existing classes. Therefore, the naming of mixins should generally be carefully considered to minimize the possibility of such conflicts.

44. Error handling, “try.. catch”

try.. The catch structure allows us to handle errors that occur during execution. Literally, it allows you to “try” the code and “catch” errors that might occur in it.

The syntax is as follows:

Try {// execute this code} catch(err) {// If an error occurs, jump to this point // err is an error object} finally {// Execute after try/catch anyway}Copy the code

There may be no catch part or no finally, so try.. Catch or try.. Finally is available.

The Error object contains the following properties:

  • Message – Human-readable error message.
  • Name – a string with an error name (the name of the error constructor).
  • Stack (no standard, but well supported) – the call stack when an Error occurs.

If we don’t need an error object, we can omit it by using catch {instead of catch(err) {.

We can also use the throw operator to generate a custom error. Technically, the argument to a throw can be anything, but it is usually an Error object that inherits from the built-in Error class. We’ll cover extended Error in more detail in the next chapter.

Rethrowing is an important pattern of error handling: A catch block usually expects and knows how to handle a particular type of error, so it should throw an error it doesn’t know about again.

Even if we don’t try.. Catch, most execution environments also allow us to set up “global” error handlers to catch “fall out” errors. In the browser, window.onerror.

45. Customize Error and extend Error

  • We can inherit normally from Error and other built-in Error classes. We just need to pay attention to the name attribute and don’t forget to call super.
  • We can use Instanceof to check for specific errors. But sometimes we have an Error object from a third-party library, and there’s no easy way to get its class here. The name attribute can then be used for this kind of checking.
  • Wrapping exceptions is a widely used technique: functions that handle low-level exceptions and create higher-level errors rather than various low-level errors. In the example above, low-level exceptions are sometimes an attribute of the object, such as err.cause, but this is not strictly required.

46. The chain of Promise

If the.then (or catch/finally) handler returns a promise, the rest of the chain will wait until its state becomes Settled. When it is settled, its result (or error) will be passed further.

Here’s a full flow chart:

47. Use promises for error handling

  • .catch handles various errors in a promise: a reject() call, or a thrown error in a handler.
  • We should put.catch exactly where we want to handle errors and know how to handle them. Handlers should analyze errors (you can customize error classes to help analyze them) and throw unknown errors again (perhaps they are programming errors).
  • If there is no way to recover from an error, you can do so without using.catch.
  • In all cases we should have unHandledrejection event handlers (for browsers, as well as simulations in other environments) to keep track of unhandled errors and inform the user (and possibly our server) about them so that our application never “dies”.

Add the content

Fetch error handling example

Let’s improve the error handling of the user-loading example.

Fetch Reject returns a promise when the request cannot be sent. For example, the remote server is unreachable, or the URL is abnormal. But if the remote server returns a response error 404, or even error 500, these are considered valid responses.

What if at line (*), the server returns a non-JSON (non-JSON) page with error 500? Without that user, what about the GitHub page that returns error 404?

fetch('no-such-user.json') // (*)
  .then(response => response.json())
  .then(user => fetch(`https://api.github.com/users/${user.name}`)) // (**)
  .then(response => response.json())
  .catch(alert); // SyntaxError: Unexpected token < in JSON at position 0
  // ...
Copy the code

So far, the code has tried to load the response data in JSON format, but it will fail anyway due to syntax errors. You can see this by executing the example above, because the file no-such-user.json does not exist.

This is a bit bad, because the error just falls on the chain, without the details of what failed and where.

So we add one more step: we should check the Response.status property with HTTP status and throw an error if it’s not 200.

class HttpError extends Error { // (1) constructor(response) { super(`${response.status} for ${response.url}`); this.name = 'HttpError'; this.response = response; } } function loadJson(url) { // (2) return fetch(url) .then(response => { if (response.status == 200) { return response.json(); } else { throw new HttpError(response); } }) } loadJson('no-such-user.json') // (3) .catch(alert); // HttpError: 404 for ... /no-such-user.jsonCopy the code
  1. We create a custom class for HTTP errors to distinguish HTTP errors from other types of errors. In addition, the new class has a constructor, which accepts a Response object and saves it to an error. Therefore, the error-handling code is able to retrieve the response data.
  2. We then wrap the requests and error handling code into a function that can fetch urls and treat any status code that is not 200 as an error. This is handy, because we usually need logic like this.
  3. Alert now displays more useful descriptions.

The benefit of having our own error-handling class is that we can use Instanceof to easily check for errors in our error-handling code.

For example, we can create a request and tell the user to modify if we get a 404.

The following code loads the user with the given name from GitHub. If there is no such user, it will tell the user to fill in the correct name:

function demoGithubUser() {
  let name = prompt("Enter a name?", "iliakan");

  return loadJson(`https://api.github.com/users/${name}`)
    .then(user => {
      alert(`Full name: ${user.name}.`);
      return user;
    })
    .catch(err => {
      if (err instanceof HttpError && err.response.status == 404) {
        alert("No such user, please reenter.");
        return demoGithubUser();
      } else {
        throw err; // (*)
      }
    });
}

demoGithubUser();
Copy the code

Note: the.catch here catches all errors, but it only “knows how to handle” HttpError 404. In that particular case, it means that there is no such user, and.catch simply retries in that case.

With other errors, it doesn’t know what the problem is. It could be a programming error or something. So it’s just thrown again at the (*) line.

other

If we have load-indications,.finally is a good handler to stop when the fetch completes:

function demoGithubUser() { let name = prompt("Enter a name?" , "iliakan"); Document. The body. The style.css. Opacity = 0.3; / / (1) the first indication (indication) return loadJson (` {name} ` https://api.github.com/users/$. Finally (() = > {/ / (2) stop instructions (indication)  document.body.style.opacity = ''; return new Promise(resolve => setTimeout(resolve)); // (*) }) .then(user => { alert(`Full name: ${user.name}.`); return user; }) .catch(err => { if (err instanceof HttpError && err.response.status == 404) { alert("No such user, please reenter."); return demoGithubUser(); } else { throw err; }}); } demoGithubUser();Copy the code

Here in line (1), we darken the document to indicate loading. There is nothing wrong with the directive method; you can use any type of directive instead.

When the promise is resolved, the fetch can be either a success or an error, and finally triggers and terminates the load instruction on line (2).

As a browser trick, (*) returns a zero-timeout promise from finally. This is because some browsers, such as Chrome, require a promise handler outside of “a little time” to draw changes to the document. So it ensures that the indicator is visually stopped before going to the next step in the chain.

48. Promise API

The Promise class has five static methods:

  1. Promise.all(Promises) — Wait until all promises are resolved, and return the array containing their results. If any given promise is reject, it becomes a promise. all error, and all other promise results are ignored.

  2. Promise.allsettled (Promises) (ES2020 New method) — Wait for all promises to settle and return their results as an array of objects containing the following:

    • Status: “fulfilled” or “rejected”
    • This is a big pity (perhaps) or reason (maybe).
  3. Promise.race(Promises) — Wait for the first Promise to settle and take its result/error as the result.

  4. Promise.resolve(value) — Create a Resolved Promise with the given value.

  5. Promise.reject(error) — Creates a Rejected Promise with the given error.

Of these five methods, Promise.all is probably the most used in real life.

49. Microtasks

Promise processing is always asynchronous, because all Promise behavior goes through an internal “Promise Jobs” queue, also known as a “microtask queue” (ES8 terminology).

Therefore, the.then/catch/finally handler is always called after the current code has completed.

If we need to ensure that a piece of code is executed after.then/catch/finally, we can add it to the.then of the chain call.

In most JavaScript engines (including browsers and Node.js), the concept of microtasks is closely related to “event loops” and “macrotasks.”

50. Async/await

The async keyword in front of the function does two things:

  1. Make this function always return a promise.
  2. Allow await inside this function.

The keyword await before the Promise causes the JavaScript engine to wait for the Promise settle, and then:

  1. If there is an error, an exception is thrown — just as throwing Error was called there.
  2. Otherwise, the result is returned.

Together, these two keywords provide a great framework for writing asynchronous code that is easy to read and write.

With async/await, we hardly need to use promise.then/catch, but don’t forget that they are promise based, because sometimes (for example in outermost scopes) we have to use these methods. Also, promise.all works well when we need to wait for a task at the same time.

51. Generator

  • Generator function* f(…) {… } create.
  • Within the generator (only within), there is a yield operation.
  • External code and the generator may exchange results through next/yield calls.

In modern JavaScript, generator is rarely used. But sometimes they come in handy, because a function’s ability to exchange data with the calling code during execution is quite unique. And, of course, they’re great for creating iterable objects.

And, in the next chapter we will learn about async generators, which are used in for await… A loop in which a stream of data is read asynchronously (for example, through paginated fetches over a network).

In Web programming, we use data flow a lot, so this is another very important usage scenario.

52. Asynchronous iteration and Generator

Regular Iterators and generators work well with data that does not take time to generate.

When we expect to get data asynchronously, with delay, we can use asynchronous versions of them and use for await.. Of alternative for.. Of.

Syntax differences between asynchronous iterators and regular iterators:

Syntax Differences between asynchronous and regular generators:

In Web development, we often encounter data flows chunk-by-chunk. For example, downloading or uploading large files.

We can use asynchronous generators to process such data. It is worth noting that in some environments, such as the browser environment, there is another API called Streams, which provides special interfaces to process such data Streams, transform data and transfer it from one data stream to another (for example, download it from one place and immediately send it elsewhere).

53. Introduction to Modules

The core concepts of the module are summarized below:

  1. A module is a file. The browser needs to use
  • The default is deferred.
  • Async can be used for inline scripts.
  • To load an external script from another source (domain/protocol/port), you need the CORS header.
  • Duplicate external scripts are ignored
  1. Modules have their own local top-level scope and can be swapped with import/export.
  2. The module always uses Use strict.
  3. Module code is executed only once. Exports are created only once and then shared between imports.

When we use modules, each module implements specific functionality and exports it. We then use import to import it directly to where we need it. The browser automatically loads and parses the script.

In production environments, developers often use packaging tools such as Webpack to package modules together for performance and other reasons.

54. Export and import

  • Declare a class/function/… Before:

    • export [default] class/function/variable …
  • Independent export:

    • export {x [as y], … }.
  • Re-export:

    • export {x [as y], … } from “module”
    • Export * from “module” (default exports will not be reexported)
    • Export {default [as y]} from “module”

Import:

  • Module named exports:

    • import {x [as y], … } from “module”
  • Default export:

    • import x from “module”
    • import {default as x} from “module”
  • All:

    • import * as obj from “module”
  • Import the module (its code, and run), but do not assign it to a variable:

    • import “module”

It doesn’t matter if we put the import/export statement at the top or bottom of the script.

So, technically speaking, there is no problem with code like this:

sayHi(); / /... import {sayHi} from './say.js'; // Import at the bottom of the fileCopy the code

In real development, imports are usually at the beginning of the file, but this is just for convenience.

Please note in {… } import/export statement is invalid.

Conditional imports like this are invalid:

if (something) {
  import {sayHi} from "./say.js"; // Error: import must be at top level
}
Copy the code

55. The Proxy and Reflect

A Proxy is a wrapper around an object, forwarding operations on the Proxy to the object, and optionally capturing some of them.

It can wrap any type of object, including classes and functions.

Grammar:

let proxy = new Proxy(target, {
  /* trap */
});
Copy the code

… Then, we should use proxy everywhere instead of target. The broker has no properties or methods of its own. If a trap is provided, it captures the operation, otherwise it is forwarded to the target object.

We can capture:

  • Read (get), write (set), delete (deleteProperty) properties (even nonexistent properties).
  • Function call (apply catcher).
  • New operation (Construct catcher).
  • Many other actions (see the beginning of this article and Docs for a full list).

This enables us to create “virtual” properties and methods, implement default values, observable objects, function decorators, and so on.

We can also wrap objects multiple times in different agents and decorate them with multiple aspects of functionality.

The Reflect API is intended to complement the Proxy. For any Proxy capture, there is a Reflect call with the same parameters. We should use them to forward the call to the target object.

Proxy has some limitations:

  • Built-in objects have “internal slots” to which access cannot be proxied. See above for solutions.
  • The same is true for private class fields, since they are also implemented internally using slots. Therefore, calls to proxy methods must have the target object as this in order to access them.
  • Object strict equality check === cannot be intercepted.
  • Performance: Benchmarks depend on the engine, but it usually takes several times longer to access properties using the simplest proxy. In fact, this is only important for certain “bottleneck” objects.

56. Traverse the DOM

Given a DOM node, we can use the navigation property to access its immediate neighbors.

These attributes fall into two main groups:

  • For all nodes: parentNode, childNodes, firstChild, lastChild, previousSibling, nextSibling.
  • Only for element nodes: parentElement, children, firstElementChild, lastElementChild, previousElementSibling, nextElementSibling.

Some types of DOM elements, such as table, provide additional attributes and collections for accessing their content.

57. Search: getElement*, querySelector*

There are six main ways to search for a node in the DOM:

Also: By far the most commonly used are querySelector and querySelectorAll, but getElement(s)By* may be occasionally useful, or can be found in older scripts.

  • Matches (CSS) checks whether elem matches a given CSS selector.
  • Closest (CSS) is used to find closest ancestors that match a given CSS selector. The ELEM itself is also checked.

Let’s mention another way to check the relationship between children and parents here, because it’s sometimes useful:

  • Returns true if elemB is inside elemA (a descendant of elemA) or elemA==elemB, elema. contains(elemB).

58. Node attributes: Type, Tag, and Content

Each DOM node belongs to a specific class. Hierarchy is formed for these classes. The complete set of properties and methods is the result of inheritance.

The main DOM node attributes are:

NodeType we can use to see whether a node is a text node or an element node. It has a numeric value: 1 for the element, 3 for the text node, and some others for other node types. Read-only.

NodeName /tagName is used for element names, tag names (all uppercase except XML schema). For a non-element node, nodeName describes what it is. Read-only.

InnerHTML The HTML content of the element. It can be modified.

OuterHTML The full HTML of the outerHTML element. The write to elem. OuterHTML does not touch the ELEm itself. Instead, replace it with the new HTML in the external context.

NodeValue /data The content of a non-element node (text, comment). It’s almost the same, we usually use data. It can be modified.

Text within the textContent element: HTML minus all. Writing text puts text inside an element, and all special characters and labels are treated as text. You can safely insert user-generated text and prevent unnecessary HTML inserts.

Hidden When set to true, performs the same thing as CSS display: None.

DOM nodes also have other attributes, which depend on their classes. For example, elements (HTMLInputElement) support value, type, and elements (HTMLAnchorElement) support href, etc. Most standard HTML attributes have corresponding DOM attributes.

59. Attributes and Properties

– Attribute – Content written in HTML. – Property – The content of a DOM object.

A brief contrast:

Elem.hasattribute (name) – Checks whether this feature exists. How to manipulate features:

– elem. GetAttribute (name) – Obtains the attribute value. – elem. SetAttribute (name, value) – Sets the attribute value. – elem. RemoveAttribute (name) – Removes this feature. – Em. attributes – A collection of all attributes.

In most cases, it’s best to use DOM attributes. Use features only when DOM attributes do not meet development requirements and we really need them, such as:

– We need a non-standard feature. But if it starts with data-, then we should use dataset. – We want to read “written” values in HTML. The corresponding DOM attribute may differ, for example, the href attribute is always a full URL, but we want the “original” value.

60. Modify document (document)

[- Create a new node method:

-document.createElement (tag) -- creates an element node with the given tag, -document.createTextNode (value) -- creates a text node (rarely used), -em.clonenode (deep) -- Clone the element, with its descendants if deep==true. - Insert and remove nodes: - node.append(... Nodes or strings) - Insert at the end of node, -node.prepend (... Nodes or strings) -- Insert at the beginning of node, -node. before(... Nodes or strings) -- Insert before node, -node.after (... Nodes or strings) -- Insert after node, -node.replacewith (... Nodes or strings) - Replaces nodes. - node.remove() - Removes a node. ] (https://link.juejin.cn?target=undefined)Copy the code

The text string is inserted “as text”.

[- Here’s the “old fashioned” way:

-   parent.appendChild(node)
-   parent.insertBefore(node, nextSibling)
-   parent.removeChild(node)
-   parent.replaceChild(newElem, node)](https://link.juejin.cn?target=undefined)
Copy the code

These methods all return Node.

[- Given some HTML in HTML, elem. InsertAdjacentHTML (where, HTML) will insert it based on the value of where:

- "beforeBEGIN" -- inserts HTML before ELEm, - "afterBEGIN" -- inserts HTML at the beginning of ELEm, - "beforeEnd" -- inserts HTML at the end of ELEm, - "afterend" - Inserts HTML after ELEm. ] (https://link.juejin.cn?target=undefined)Copy the code

. In addition, there is a similar approach, elem insertAdjacentText and elem insertAdjacentElement, they will insert a text string and elements, but rarely used.

[- To attach HTML to the page before the page loads:

-   document.write(html)](https://link.juejin.cn?target=undefined)
Copy the code

After the page has loaded, such a call erases the document. Often seen in older scripts.

61. Styles and classes

To manage classes, there are two DOM attributes:

– className – A string value that can manage the entire collection of classes. – classList – with the add/remove/toggle/the contains method of object, is a good way to support a single class.

To change the style:

To read the Resolved style (for all classes, after applying all CSS and calculating the final value) :

  • GetComputedStyle (elem, [pseudo]) returns an object similar to the Style object, containing all classes. Read-only.

62. Element size and scrolling

The element has the following geometric properties:

  • OffsetParent – is the ancestor of the closest CSS location, or TD, TH, table, body.
  • OffsetLeft /offsetTop – is the coordinates of the upper-left edge relative to offsetParent.
  • OffsetWidth /offsetHeight – The “outer” width/height of the element, including the border size, is counted.
  • ClientLeft /clientTop – The distance from the upper left outer corner of the element to the upper left inner corner. For an operating system that displays content left to right, they are always the width of the left/top border. For an operating system that displays content from right to left, the vertical scroll bar is on the left, so clientLeft also includes the width of the scroll bar.
  • ClientWidth /clientHeight – Width/ height of the content, including padding but not scrollbar.
  • ScrollWidth /scrollHeight – The width/height of the content, just like clientWidth/clientHeight, but also includes the scrolling out of the invisible part of the element.
  • ScrollLeft /scrollTop – Starting at the upper left corner of the element, scroll out the width/height of the upper half of the element.

All attributes except scrollLeft/scrollTop are read-only. If we modify scrollLeft/scrollTop, the browser will scroll the corresponding element.

63. Window size and scrolling

Geometry:

  • Document the visible parts of the width/height (width/height) of the content area: the document. The documentElement. ClientWidth/clientHeight

  • Width /height of the entire document, including parts that scroll out:

    let scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight );

Rolling:

  • Read the current scroll: window. PageYOffset/pageXOffset.

  • Change the current scroll:

    • Window.scrollto (pageX,pageY) — Absolute coordinates,
    • Window.scrollby (x,y) — scroll relative to the current position,
    • Elem. ScrollIntoView (top) – Scroll to make elem visible (eleM aligned with the top/bottom of the window).

64. Overview of browser events

There are three ways to assign event handlers:

  1. Onclick =”…” .
  2. DOM property: em.onclick = function
  3. Method: em.addeventListener (Event, Handler [, Phase]) for adding and removeEventListener for removing.

The HTML feature is rarely used because JavaScript in HTML tags looks strange and unfamiliar. And you can’t write too much code in there.

DOM attributes work fine, but we can’t assign more than one handler to a particular event. In many scenarios, this limitation is not severe.

This last option is the most flexible, but also the longest to write. There are a few events that can only be used this way. Examples include Transtionend and DOMContentLoaded (mentioned above). AddEventListener also supports objects as event handlers. In this case, if an event occurs, the handleEvent method is called.

No matter how you classify the handler — it will get an event object as its first argument. This object contains detailed information about the event that occurred.

65. Bubble and capture

When an event occurs — the deepest nested element in which the event occurred is marked as “event.target.”

  • The event is then moved down from the document root node to event.target with an addEventListener(… , true) (true is a shorthand for {capture: true}).
  • The handler is then invoked on the target element itself.
  • The event then bubbles from event.target to the root, calling handlers assigned using ON, HTML attributes, and addEventListener with no third argument, or false/{capture:false}.

Each handler has access to the properties of the Event object:

  • Event.target – The deepest level element that raises the event.
  • Event.currenttarget (=this) — The current element that handles the event (the element with the handler)
  • Event.eventphase — Current phase (capturing=1, Target =2, Bubbling =3)

Any event handler can stop events by calling event.stopPropagation(), but this is not recommended, as we are not sure if events are really not needed to bubble up, perhaps for completely different things.

The capture phase is rarely used, and usually we process events while bubbling. There is a logic behind this.

In the real world, when an accident occurs, local police are the first to respond. They know best where it happened. Then, if necessary, the higher authorities will deal with it.

The same is true for event handlers. Set up the handler code on a particular element to learn the most detailed information about that element. A specific handler that knows everything about the element might just be appropriate for that. So the handler should be given a chance first. Then, its immediate parent element also knows the context, but less, and so on, until it processes the general concepts and runs the topmost element of the last handler.

66. Event delegation

It is often used to add the same processing to many similar elements, but is not limited to that.

Algorithm:

  1. Put a handler on a container.
  2. In the handler — check the source element event.target.
  3. If the event occurs within the element we are interested in, process the event.

Benefits:

  • Simplify initialization and save memory: no need to add many handlers.
  • Less code: No add/remove handlers are required to add or remove elements.
  • DOM modification: You can add/remove elements in batches using something like innerHTML.

Event delegation also has its limitations:

  • First, the event must bubble up. And some events don’t bubble up. In addition, low-level handlers should not use Event.stopPropagation ().
  • Second, delegates can increase CPU load because container-level handlers react to events anywhere in the container, regardless of whether we are interested in the event or not. However, the load is usually negligible, so we don’t consider it.

67. Default browser behavior

There are many default browser behaviors:

  • Mousedown – Start selection (move the mouse to select).
  • Click on — check/deselect input.
  • Submit — Clicking or pressing Enter in a form field triggers the event, after which the browser submits the form.
  • Keydown — Pressing a key causes characters to be added to a field, or triggers other behavior.
  • Contextmenu – the event occurs when a right mouse click triggers the action of displaying the browser contextmenu.
  • … And there’s more…

If we only want to handle events through JavaScript, then all default behaviors can be blocked.

To prevent the default behavior — use event.preventDefault() or return false. The second method applies only to handlers allocated by ON.

The passive: True option for addEventListener tells the browser that the action will not be blocked. This is useful for certain mobile events, like TouchStart and TouchMove, to tell the browser that it should not wait for all handlers to complete before scrolling.

The value of event.defaultspoiled becomes true if the default behavior is blocked, false otherwise.

68. Create custom events

To generate an event from code, we first need to create an event object.

The generic Event(name, options) constructor accepts an arbitrary Event name and an Options object with two properties:

  • If the event should bubble, bubbles: true.
  • If event.preventdefault () should be valid, cancelable: true.

Other constructors of native events, such as MouseEvent and KeyboardEvent, accept attributes specific to that event type. For example, clientX for mouse events.

For custom events, we should use the CustomEvent constructor. It has an additional option called detail to which we should assign event-specific data. All handlers can then access it in the form of event.detail.

Although it is technically possible to generate browser events like Click or KeyDown, they should be used with caution.

We should not generate browser events because this is a weird hacky way to run handlers. Most of the time, this is bad architecture.

Native events can be generated:

  • This is a dirty trick needed to make third-party libraries work if they don’t provide other ways to interact.
  • For automated tests, “click the button” in the script and see if the interface responds correctly.

Custom events with our own names are usually created for architectural purposes to indicate what is happening inside menus, sliders, carousels, etc.

69. Mouse events

Mouse events have the following properties:

  • Button: Button.

  • Key combination (true if pressed) : altKey, ctrlKey, shiftKey and metaKey (Mac).

    • If you want to deal with Ctrl, so don’t forget that Mac users, they are often use the Cmd, so it’s best to check the if (e.m etaKey | | e.c. with our fabrication: trlKey).
  • Window relative coordinates: clientX/clientY.

  • Document relative coordinates: pageX/pageY.

The default browser action for Mousedown is text selection, and should be avoided if it’s bad for the interface.

70. Move mouse: mouseover/out, mouseEnter /leave

Here are some things to watch out for:

  • Moving the mouse quickly may skip the middle element.
  • The mouseover/ Out and MouseEnter/Leave events have an additional attribute: relatedTarget. This is our element from/to, which complements target.

The mouseover/ Out event is triggered even when we go from parent to child. Browsers assume that the mouse will only be on one element at a time — the deepest one.

The mouseenter/ Leave events are different in this respect: they fire only when the mouse enters and leaves the element. And they don’t bubble.

71. Event: change, input, cut, copy, paste

Data change event:

Transfer: juejin. Cn/post / 698545…