preface

The main focus of reading the Little Red Book is to test exercises and supplement knowledge, but some concepts and understandings are also described in words, so the code accounts for more. Test source code address

  • What is recorded: some unfamiliar, some unknown, and some purely supplementary chapter content.
  • There is much more to the Little Red Book than that, and the order and content of the readings are based on the reference reading suggestions.
  • After settling for a while, continue reading for the second time, including the rest of the section and further sections.

Chapter 1 – What is JavaScript

JavaScript implementation

The implementation of JavaScript consists of three parts: ECMAScript (core), DOM (Document Object Model), and BOM (browser object Model).

  • ECMAScript is the name for a language specification that describes syntax, types, statements, keywords, reserved words, operators, and global objects.

  • DOM (Document Object Model) is an application programming interface for manipulating HTML.

  • The Browser Object Model (BOM) is used to access and operate the Browser window.

Chapter 2 – JavaScript in HTML

Script element

The async and defer properties
  • Async means that you should start downloading scripts immediately, but does not block other page actions (the order of execution is variable), only for external files.

  • Defer means that the script is executed after the document has been parsed and displayed (pushing execution to the bottom), and only applies to external files.

  • By default,

As you can see: The loading order is fixed.

<script src="./defer.js"></script>
<script src="./async.js"></script>
<script src="./default.js"></script>
<! -- defer async default -->
<! -- defer async default -->
<! -- defer async default -->
Copy the code

As you can see: the order of async is not fixed, and defer has always followed default.

<script defer src="./defer.js"></script>
<script async src="./async.js"></script>
<script src="./default.js"></script>
<! -- async default defer-->
<! -- default defer async-->
<! -- default async defer-->
Copy the code
The type attribute specifies the module

ES6 modules can be used by specifying type=”module” in

<script type="module">
  import num from "./main.js";
</script>
Copy the code

Noscript elements

The TAB is displayed when the browser does not support scripting or when browser support for scripting is disabled.

<noscript>
  <strong>Your browser does not support JavaScript or is not JavaScript enabled.</strong>
</noscript>
Copy the code

Chapter 3 – Language Basics

Variable declarations

  • Var declarations: Variables declared using VAR are automatically promoted to the top of the function scope, or global if they are not in the function.

  • Let declaration: The difference between let and var is The scope of the let declaration is block scope, and variables declared by the let are not promoted in scope. The period of execution prior to the let declaration is called a “temporary dead zone” in which variables declared after reference are reported as errors.

  • Const: Const is basically the same as let, with the important difference that variables (constants) declared by const must be assigned an initial value and cannot be changed later.

The data type

  • Simple data types:Undefind.Null.Boolean.Number , String , Symbol.
  • Complex data types:Object.

Label statement

Label statements for later invocation. Both break and continue can be used for scenarios in nested loops.

let num1 = 0;
outermost: for (let i = 0; i < 5; i++) {
  for (let j = 0; j < 5; j++) {
    if (i === 1 && j === 1) {
      break outermost; // End the loop at layer I.} num1++; }}console.log(num1); / / 6

let num2 = 0;
for (let i = 0; i < 5; i++) {
  for (let j = 0; j < 5; j++) {
    if (i === 1 && j === 1) {
      break; // The loop can only be completed at layer J.} num2++; }}console.log(num2); / / 21
Copy the code

With statement

Sets the scope of the code to a specific object, which is not allowed in strict mode.

function WithThis() {
  this.name = "lian";
  this.age = 23;
  this.getUserInfo = function () {
    with (this) {
      return {
        name: name,
        age: age, }; }}; }const withThis = new WithThis();

console.log(withThis.getUserInfo()); // { name: 'lian', age: 23 }
Copy the code

Chapter 5 – Basic Reference Types

RegExp constructor property

The RegExp constructor property also has properties of its own that change based on the last regular expression operation performed.

If nine capture groups are stored, these attributes can be accessed through RegExp.$1 to RegExp.$9.

let text = "2020-11-29";
let pattern = /(\d{4})-(\d{2})-(\d{2})/g;

pattern.test(text);

console.log(RegExp. $1);/ / 2008
console.log(RegExp. $2);/ / 12
console.log(RegExp. $3);/ / 31
console.log(RegExp$4);/ / ""
Copy the code

Raw value wrapper type

We know that simple data types (also known as primitive types) contain Undefind, Null, Boolean, Number, String, and Symbol.

To facilitate manipulation of raw values, ECMAScript provides three primitive value wrapper types: Boolean, Number, and String, all of which have special behavior corresponding to their respective primitive types.

let s1 = "text";
let s2 = s1.substring(2);
console.log(s2); // xt
Copy the code
let s3 = new String("text");
let s4 = s3.substring(2);
console.log(s4); // xt
Copy the code

The results from the above code are the same, but we know that the original values themselves are not objects, so logically there should be no methods. This is because the following three steps are performed at execution time.

  1. To create aStringType.
  2. Invoke a specific method on the instance.
  3. Destroy the instance.
let s1 = new String("text");
let s2 = s1.substring(2);
s1 = null;
Copy the code

Automatically created raw value wrapper object. Only the line of code that accesses it exists during execution, meaning that a value cannot add attributes and methods to the original value.

let s5 = "text";
s5.color = "red";
console.log(s5.color); // undefined
Copy the code

A manually created wrapper type will not destroy itself.

let s6 = new String("text");
s6.color = "red";
console.log(s6.color); // red
Copy the code

Chapter 6 – Collection Reference Types

An array of space

Here is an array of data of length 5. There is no value between ‘,’ and ‘,’ to identify space.

let arr = [1.5];
Copy the code

The method prior to ES6 ignored vacancies. Methods after ES6 treat empty Spaces as undefined.

console.log(arr.indexOf(undefined)); // -1

console.log(arr.includes(undefined)); // true
Copy the code

In practice, if a vacancy is needed, it can be explicitly specified as undefined.

Set/WeakSet/Map/WeakMap

Set and Map are new data structures added to ES6. They all operate using the SameValueZero (same-value zero) comparison algorithm.

Set

It is similar to an array, but the values of the members are unique and there are no duplicate values, such as incoming and outgoing.

let s1 = [2.3.5.4.5.2.2];
let s2 = new Set(s1);

s2.add(+0);
s2.add(-0);

console.log([...s2]); // [2, 3, 5, 4, 0]
Copy the code
Map

It is a collection of key-value pairs similar to objects, but the range of “keys” is not limited to strings. Values of all types (including objects) can be used as keys.

let m1 = new Map(a);let m2 = { p: "Hello World" };

m1.set(m2, "content");

console.log(m1.get(m2)); // content
Copy the code
Weak

The “Weak” in WeakSet and WeakMap describes the way that JavaScript garbage collection treats the key in “If map”.

let map = new Map(a);let button = document.querySelector("button");
map.set(button, { disabled: false });
Copy the code

Suppose the DOM above is deleted, but since the button reference is still in the map, the corresponding DOM node remains in memory after deletion.

If “if mapping” is used here, the garbage collection will release the contents of the corresponding DOM node as soon as it is deleted (provided that the object is not referenced elsewhere).

Chapter 10 – Functions

The function name

All function objects expose a read-only name attribute.

function foo() {}
let bar = function () {};
let baz = () = > {};
console.log(foo.name); // foo
console.log(bar.name); // bar
console.log(baz.name); // baz
Copy the code

If created using the Function constructor, it will be identified as “anonymous”.

let anony = new Function(a);console.log(anony.name); // anonymous
Copy the code

If it is a get function, set function, or bind, the identity is preceded by a prefix.

function foo() {}
console.log(foo.bind(null).name); // bound foo
Copy the code
let info = {
  num: 1.get age() {
    return this.num;
  },
  set age(num) {
    this.num = num; }};let descriptor = Object.getOwnPropertyDescriptor(info, "age");
console.log(descriptor.get.name); // get age
console.log(descriptor.set.name); // set age
Copy the code

Default parameter scope with temporary dead zone

Because the parameters are initialized in order, all parameters with default values defined later can refer to those defined first.

function makeKing(name = "Henry", numerals = name) {
  return `King ${name} ${numerals}`;
}

console.log(makeKing()); // King Henry Henry
Copy the code

The initialization order of parameters follows the “temporary dead zone” rule, that is, parameters defined earlier cannot reference those defined later.

function makeKing(numerals = name, name = "Henry") {
  return `King ${name} ${numerals}`;
}

console.log(makeKing()); // ReferenceError: Cannot access 'name' before initialization
Copy the code

Detect how a function is called

A new. Target attribute that detects whether a function is called using the new keyword has been added to ES6.

If the function is called normally, the value of new.target is undefined. If it is called with the new keyword, new.target refers to the constructor being called.

function Foo() {
  return new.target;
}
console.log(Foo()); // undefined
console.log(new Foo()); // function Foo() { return new.target }
Copy the code

recursive

Recursive functions usually take the form of a function calling itself by name, as shown in the following example.

function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * factorial(num - 1); }}Copy the code

But assigning this function to another function can cause problems.

let otherFactorial = factorial;
factorial = null;
otherFactorial(2); // TypeError: factorial is not a function
Copy the code

You can use arguments.callee to point to a pointer to the function being executed.

function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * arguments.callee(num - 1); }}Copy the code

But arguments.callee cannot be used in strict mode, so you can use named function expressions to do the job.

let factorial = function f(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * f(num - 1); }};Copy the code

closure

Closures are usually implemented in nested functions, meaning that the inner function refers to a variable in the scope of the outer function, and the returned inner function is referenced by the outer function to form a closure.

function outside() {
  let num = 1;
  // return function (add) {
  // return (num += add);
  // };
  return function inner(add) {
    return (num += add);
  };
}

let inner = outside();
console.log(inner(1)); / / 2
console.log(inner(1)); / / 3
console.log(inner(1)); / / 4

// Free memory by destroying references to functions.
inner = null;
Copy the code
Scope chain references

In the above example, two scope chains “outside” and “inner” are generated.

  • A NUM active object is generated in the scope chain of “outside”.

  • In “inner” add num active objects from the “outside” scope chain to its own scope chain.

  • After the outside function completes execution, the scope chain of its execution context is destroyed. But because there are still references to num in the “inner” scope chain, undestructible will remain in memory until the inner function is destroyed.

Chapter 12 -BOM

Query string

Query strings are parsed into objects.

function getQueryString() {
  let qs = location.search.length > 0 ? location.search.substring(1) : "";
  let args = {};
  for (let item of qs.split("&").map((kv) = > kv.split("="))) {
    let name = decodeURIComponent(item[0]);
    let value = decodeURIComponent(item[1]);
    args[value] = name;
  }
  return args;
}
console.log(getQueryString()); // {1: "id", 2: "name"}
Copy the code

If you use URLSearchParams, you provide a standard set of methods.

// location.search = "? id=1&name=2"
let searchParams = new URLSearchParams(location.search);
console.log(searchParams.get("id")); / / 1
searchParams.set("id"."11");
console.log(searchParams.get("id")); / / 11
searchParams.delete("id");
console.log(searchParams.get("id")); // null
Copy the code

Chapter 14 -DOM

MutationObserver

MutationObserver allows you to view the document, part of the DOM tree, or an element, as well as element attributes, child nodes, and text.

// Create a MutationObserver instance to execute the registered callback asynchronously
let observer = new MutationObserver((mutationRecords) = > {
  console.log(mutationRecords[0]); // {type: "attributes", target: body.foe3e3o, ... }
});

// Set the object to be observed
observer.observe(document.body, {
  subtree: true.attributes: true.// ...
});
document.body.className = "foo";

// Cancel the observed object
setTimeout(() = > {
  observer.disconnect();
  document.body.className = "bar";
  // (no log output)
});

// Clear the queue
setTimeout(() = > {
  observer.takeRecords();
});
Copy the code

Chapter 15 -DOM Extensions

classList

HTML5 provides an easier way to manipulate types by adding classList attributes to all elements.

  • Add: Adds the specified string value to the list of class names, and does nothing if the value already exists.
  • Contains: Returns a Boolean value indicating whether the given string exists.
  • Remove: Removes the specified string value from the list.
  • Toggle: Removes the specified value if it already exists in the class list. If it does not exist, add it.
<div id="box"></div>
<script>
  box.classList.add("disabled");
  console.log(box.classList.contains("disabled")); // true
  box.classList.remove("disabled");
  console.log(box.classList.contains("disabled")); // false
</script>
Copy the code

insertAdjacentHTML

Insert tags, which can be strings that are automatically parsed to HTML.

  • Beforebegin: Inserts before the current element as the previous sibling node.
  • Afterbegin: Inserts inside the current element as a new child or before the first child.
  • Beforeend: Inserts inside the current element as a new child node or before the last child node.
  • Afterend: Inserts after the current element as the next sibling node.
<ul id="ul">
  <li id="li"></li>
</ul>
<script>
  li.insertAdjacentHTML("beforebegin", "<li>Inserts before the current element as the previous sibling node.</li>");
  console.log(ul.innerHTML); // <li>Inserts before the current element as the previous sibling node.</li> <li id="li"></li>
</script>
Copy the code

insertAdjacentText

InsertAdjacentText has the same configuration as insertAdjacentHTML.

<div id="text">insertAdjacentText</div>
<script>
  text.insertAdjacentText("afterbegin"."Insert before current text.");
  console.log(text.innerHTML); // Insert before the current text. insertAdjacentText
</script>
Copy the code

scrollIntoView

ScrollIntoView exists on all elements and can scroll through browser Windows or containers. Makes the element enter the viewport.

  • Behavior: Defines the transition animation. The options are “smooth” or “auto”.
  • Block: Define vertical alignment, optional “start”/”center”/”end”/”nearest”.
  • Inline: Defines horizontal alignment with “start”/”center”/”end”/”nearest” options.
<div style="height: 2000px">
  <button id="button" style="margin-top: 1000px">Appear in the visible area</button>
</div>
<script>
  // The top of the element is aligned with the top of the viewport after the window scrolls
  button.scrollIntoView(true);
  button.scrollIntoView({ block: "start" });

  // The bottom of the element is aligned with the bottom of the viewport after the window scrolls
  button.scrollIntoView(false);
  button.scrollIntoView({ block: "end" });

  button.scrollIntoView({
    behavior: "smooth".block: "center".inline: "center"});</script>
Copy the code

Chapter 17 – Events

Flow of events

The sequence of stages in the event flow is: event capture (from outside in) => reach target => Event bubble (from inside out). Using addEventListener, you can easily control when events are triggered at that stage.

The bubble phase is triggered when three arguments are false (default). The trigger order when clicking inner is inner => box.

<div id="box" style="padding: 100px; background: red">
  <button id="inner">Click on the</button>
</div>
<script>
  box.addEventListener(
    "click".() = > {
      console.log("box");
    },
    false
  );
  inner.addEventListener(
    "click".() = > {
      console.log("inner");
    },
    false
  );
</script>
Copy the code

The capture phase is triggered when three arguments are true. The trigger order when clicking inner is box => inner.

<div id="box" style="padding: 100px; background: red">
  <button id="inner">Click on the</button>
</div>
<script>
  box.addEventListener(
    "click".() = > {
      console.log("box");
    },
    true
  );
  inner.addEventListener(
    "click".() = > {
      console.log("inner");
    },
    true
  );
</script>
Copy the code

Event delegation

Event delegation is based on the principle of event bubbling. When an inner element is clicked, it will bubble to the outer element and process the corresponding event by judging the event source.

<ul id="ul">
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>
<script>
  ul.addEventListener("click".function (ev) {
    // Process compatibility
    let event = ev || window.event;
    let target = ev.target || ev.srcElement;
    // Determine the event source type
    if (target.nodeName.toLowerCase() === "li") { alert(target.innerHTML); }});</script>
Copy the code

Custom events

The book says createEvent but many of the methods used are obsolete. View MDN events and CustomEvents.

<div id="div"></div>
<script>
  let event = new Event("look", { bubbles: true });
  document.dispatchEvent(event);

  // Events can be fired at any element, not just document
  div.addEventListener("look".function () {
    console.log("look");
  });
  div.dispatchEvent(event); // "look"
</script>
Copy the code

Chapter 23 -JSON

serialization

With the second argument, each key-value pair of the object is processed by the function first.

let s = { name: "lian".age: 22.status: true };
let s1 = JSON.stringify(s, (key, value) = > {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value;
});
console.log(s1); // {"name":"LIAN","age":22,"status":true}
Copy the code

Sometimes, if you want to customize the JSON serialization on an object, you can add the toJSON() method to the serialized object.

let sto = {
  name: "lian".age: 22.status: true.toJSON() {
    return this.age * 2; }};console.log(JSON.stringify(sto)); / / 44
Copy the code

parsing

With the second argument, each key-value pair of the object is processed by the function first.

let sp = '{"name":"lian","age":22,"status":true}';
sp1 = JSON.parse(sp, function (key, value) {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value;
});
console.log(sp1); // { name: 'LIAN', age: 22, status: true }
Copy the code

Chapter 24 – Network Requests and Remote Resources

This chapter for the network request is not very familiar with the students (such as me), the basic is new knowledge, and more configuration, the specific content can read. Here are examples of each request, including the front and back ends.

Ajax

Back-end (nodeJS)

const express = require("express");
const app = express();

app.use(express.static(__dirname + "/public"));

app.get("/api".function (req, res) {
  res.send("hello world");
});

app.listen(3000.function () {
  console.log("listen at 3000");
});
Copy the code

The front end

// Create an XHR object
let xhr = new XMLHttpRequest();
// Request phase changes readyState indicates at that phase
// 0 = uninitialized; 1 = "xhr.open"; 2 = "xhr.send" has been sent; 3 = Receiving; 4 = completed
xhr.onreadystatechange = function (event) {
  console.log(xhr);
  if (xhr.readyState === 4) {
    console.log(xhr.response); // hello world}};// Send the defined request
xhr.open("get"."/api".true);
xhr.send(null);
Copy the code

Fetch

Back-end (nodeJS)

const express = require("express");
const app = express();

app.use(express.static(__dirname + "/public"));

app.get("/api".function (req, res) {
  res.send("hello world");
});

app.post("/api/json".function (req, res) {
  res.send({ hello: "world" });
});

app.listen(3000.function () {
  console.log("listen at 3000");
});
Copy the code

The front end

fetch("/api", {
  method: "GET",
}).then((response) = > {
  // Get the TEXT format
  response.text().then((text) = > {
    console.log(text); // hello world
  });
});

fetch("/api/json", {
  method: "POST",
}).then((response) = > {
  // Get the JSON format
  response.json().then((text) = > {
    console.log(text); // {hello: "world"}
  });
});
Copy the code

WebSocket

Back-end (nodeJS)

const express = require("express");
const app = express();
const WebSocketServer = require("ws").Server;

// Create the Socket service
const wss = new WebSocketServer({ port: 4000 });
wss.on("connection".function (ws) {
  ws.on("message".function (message) {
    // After receiving the message, return directly.
    ws.send(message);
  });
});

app.use(express.static(__dirname + "/public"));
app.listen(3000.function () {
  console.log("listen at 3000");
});
Copy the code

The front end

let socket = new WebSocket("ws://localhost:4000");
socket.onmessage = function (event) {
  console.log(event.data); // Listen for messages
  / / 1607350727238
  / / 1607350732235
  // ...
};
socket.onopen = function () {
  setInterval(() = > {
    socket.send(Date.now()); // Send a message
  }, 5000);
};
Copy the code

Chapter 25 – Client Storage

Cookie

Session cookies are cleared when the browser closes.

document.cookie = "name=lian";
Copy the code

Sets the expires time.

// Sets' expires' to expire.
let date = new Date(a); date.setDate(date.getDate() +1);
document.cookie = "name=lian; expires=" + date;
Copy the code

Cookies should not cause problems in browsers as long as they comply with the following general restrictions (which vary by browser).

  • No more than 300 cookies.
  • Each cookie does not exceed 4096 bytes.
  • There are no more than 20 cookies per field.
  • Each field does not exceed 81920 bytes.

sessionStorage/localStorage

The sessionStorage object only stores session data, which is cleared by closing the browser, similar to session cookies.

sessionStorage.setItem("name"."lian");
console.log(sessionStorage.getItem("name")); // lian
sessionStorage.removeItem("name");
console.log(sessionStorage.getItem("name")); // null
Copy the code

LocalStorage Persistent data stores that are not cleared with browser closure and have no expiration time. It has the same API as sessionStorage.

localStorage.setItem("name"."lian");
console.log(localStorage.getItem("name")); // lian
localStorage.removeItem("name");
console.log(localStorage.getItem("name")); // null
Copy the code

SessionStorage and localStorage have a maximum browsing limit of 5M per domain.

storageEvent

Any API that calls localStorage under the same name and on different pages fires a storage event.

// event.html
window.addEventListener("storage".(event) = > {
  console.log(event.url); // Store the domain corresponding to the change
  console.log(event.key); // The key to be set or deleted
  console.log(event.newValue); // The value after the key change, or null if the key is deleted
  console.log(event.oldValue); // The value before the key changes
});
Copy the code
// submit.html
localStorage.setItem("name".Date.now());
Copy the code

Chapter 16 -DOM2 and DOM3

Comparison of the node

DOM3 added two methods for comparing nodes isSameNode() same, isEqualNode() equal.

let div1 = document.createElement("div");
div1.setAttribute("class"."box");

let div2 = document.createElement("div");
div2.setAttribute("class"."box");

console.log(div1.isSameNode(div1)); // true
console.log(div1.isEqualNode(div2)); // true
console.log(div1.isSameNode(div2)); // false
Copy the code

Calculate the style

DOM2 adds the getComputedStyle() method on Document.defaultView to get all the computed styles of an element.

<style>
  #box {
    width: 100px;
    height: 100px;
    background-color: red;
  }
</style>
<body>
  <div id="box"></div>
  <script>
    let box = document.querySelector("#box");
    let computedStyle = document.defaultView.getComputedStyle(box, null);
    console.log(computedStyle); // CSSStyleDeclaration { width, height, color, margin, ... }
    console.log(computedStyle.width); // 100px
    console.log(computedStyle.height); // 100px
    console.log(computedStyle.color); // RGB (0, 0, 0) will get the default if not set
  </script>
</body>
Copy the code

The second argument can be passed to the pseudo-element string (for example: “:after”) to get the pseudo-element style.

<style>
  #box:after {
    font-size: 30px;
  }
</style>
<body>
  <div id="box"></div>
  <script>
    let boxAfter = document.querySelector("#box");
    let computedStyleAfter = document.defaultView.getComputedStyle(box, ":after");
    console.log(computedStyleAfter.fontSize); // 30px
  </script>
</body>
Copy the code

Determining element size

On each element there is the getBoundingClientRect() method, which returns a DOMRect object with properties that give the element’s position on the page relative to the viewport (left and top).

<style>
  * {
    margin: 0px;
    padding: 0px;
  }
  #box {
    position: absolute;
    top: 100px;
    left: 100px;
    width: 100px;
    height: 100px;
    background: red;
  }
</style>
<body>
  <div id="box"></div>
  <script>
    let DOMRect = box.getBoundingClientRect();
    console.log(DOMRect);
    / / {
    // top: 100;
    // left: 100;
    // width: 100;
    // height: 100;
    // bottom: 200; // = top + height
    // right: 200; // = left + width
    // x: 100;
    // y: 100;
    // }
  </script>
</body>
Copy the code

Chapter 20 -JavaScript apis

File API

FileReader

The FileReader type indicates the asynchronous file reading mechanism.

  • FileReader.readAsText()After reading the contents of the file, the result property will holdstringFile contents.
  • FileReader.readAsDataURL()After reading the contents of the file, the result property will holdBase64 stringFile contents.
  • FileReader.readAsArrayBuffer()After reading the contents of the file, the result property will holdArrayBufferData objects.
  • FileReader.readAsBinaryString()After reading the contents of the file, the result property will holdRaw binary dataFile contents.
Image selection preview
<body>
  <input id="upload" type="file" value="Select picture" />
  <img id="image" src="" alt="" />
  <script>
    upload.addEventListener("change".(event) = > {
      console.log(event.target.files); // [ File ]

      let file = event.target.files[0];
      let reader = new FileReader();

      if (/image/.test(file.type)) {
        reader.readAsDataURL(file);
      }

      reader.onload = function () {
        image.src = reader.result;
        console.log(reader.result); // data:image/png; base64,iVBORw0KGg
      };
    });
  </script>
</body>
Copy the code
Image drag preview

This listens for the target source event, which is triggered when a drag element is pulled on the target element.

<style>
  #upload {
    width: 100px;
    height: 100px;
    line-height: 100px;
    font-size: 50px;
    text-align: center;
    border: 1px solid #cccccc;
  }
</style>
<body>
  <div id="upload">+</div>
  <img id="image" src="" alt="" />
  <script>
    // Enter the target element trigger
    upload.addEventListener("dragenter".function (event) {
      event.preventDefault();
      upload.style.background = "red";
    });

    // Keep firing at the target element
    upload.addEventListener("dragover".function (event) {
      event.preventDefault();
    });

    // Exit the target element
    upload.addEventListener("dragleave".function (event) {
      event.preventDefault();
      upload.style.background = "";
    });

    // Place it on the target element
    upload.addEventListener("drop".function (event) {
      event.preventDefault();
      upload.style.background = "";

      console.log(event.dataTransfer.files); // [ File ]

      let file = event.dataTransfer.files[0];
      let reader = new FileReader();

      if (/image/.test(file.type)) {
        reader.readAsDataURL(file);
      }

      reader.onload = function () {
        image.src = reader.result;
        console.log(reader.result); // data:image/png; base64,iVBORw0KGg
      };
    });
  </script>
</body>
Copy the code

Web Component

HTML Template

Define the DOM template and render the template as needed.

<body>
  <template id="tpl">
    <h1>HTMLTemplate</h1>
  </template>
  <! -- You can see it in the browser review element -->
  <! -- <template id="tpl"> #document-fragment <h1>HTMLTemplate</h1> </template> -->
  <script>
    tpl = document.querySelector("#tpl").content;
    document.body.appendChild(tpl);
  </script>
</body>
Copy the code
Shadow DOM

You can build an entire DOM tree and add it to the parent DOM as child nodes. DOM encapsulation is also implemented, CSS and JS scopes are in the Shadow DOM.

<body>
  <div id="box"></div>
  <! -- You can see it in the browser review element -->
  <! -- <div id="box"> #shadow-root (open) <div>ShadowDOM</div> </div> -->
  <script>
    let ele = box.attachShadow({ mode: "open" });
    ele.innerHTML = `
      <div>ShadowDOM</div>
      <style> * { color: red; } <\/style>
      <script> var num = 0; <\/script>
    `; console.log(window.num); // undefined </script>
</body>
Copy the code
Custom elements

The power of a custom element comes from the class definition, and you can control the behavior of each instance of that class in the DOM through the constructor of a custom element.

<body>
  <x-foo>1</x-foo>
  <x-foo>2</x-foo>
  <script>
    class FooElement extends HTMLElement {
      constructor() {
        super(a);console.log(this); // x-foo: this points to this component
      }
    }
    customElements.define("x-foo", FooElement);
  </script>
</body>
Copy the code
Integrated application/input validation components

HTML Template, Shadow DOM, and custom elements are used together to implement input validation.

<body>
  <! Define component templates -->
  <template id="x-input-tpl">
    <input value="" placeholder="Please enter a number" />
  </template>
  <! -- Use input component -->
  <x-input id="input1"></x-input>
  <x-input id="input2"></x-input>
  <script>
    class xInput extends HTMLElement {
      constructor() {
        super(a);// Get the component template
        let tpl = document.querySelector("#x-input-tpl").content;
        // Add shadow DOM
        let root = this.attachShadow({ mode: "open" }).appendChild(tpl.cloneNode(true));
        // Save the input element
        this.$el = this.shadowRoot.querySelector("input");
        // Listen for data changes
        this.$el.addEventListener("input".(event) = > {
          this.value = event.target.value;
        });
      }
      get value() {
        return this.$el.value;
      }
      set value(val = "") {
        this.$el.value = val.replace(/[^0-9]/g."");
      }
    }
    customElements.define("x-input", xInput);
  </script>
  <script>
    // Get components and set values and values
    let input1 = document.querySelector("#input1");
    input1.value = "111.ss";
    console.log(input1.value); / / 111

    // Get components and set values and values
    let input2 = document.querySelector("#input2");
    input2.value = "222.ss";
    console.log(input2.value); / / 222
  </script>
</body>
Copy the code

Chapter 21 – Error Handling and Debugging

Wrong type

// Uncaught [name]: [message]
throw new Error("Base type, other error type base type.");
throw new InternalError("Thrown by the browser when the underlying JavaScript engine throws an exception (cannot be called manually)");
throw new EvalError("Thrown when an exception occurs using the eval function.");
throw new RangeError("Thrown when value is out of bounds");
throw new ReferenceError("Occurs when the object is not reached.");
throw new SyntaxError("Occurs when a syntax error occurs");
throw new TypeError("Type not expected type");
throw new URIError("Misformatted URI passed using encodeURI() or decodeURI()");
Copy the code

Custom error types

class CustomError extends Error {
  constrouctor(message) {
    supper(message);
    this.name = "CustomError";
    this.message = message; }}throw new CustomError("Custom error types"); // CustomError: CustomError type
Copy the code

Chapter 28 – Best Practices

“Best practice” is in quotes because it’s not impossible to be better on this basis.

maintainability

  • Easy to understand: It is easy to know what it does and how it is implemented without asking the original developer.
  • Common sense: Everything in the code makes sense.
  • Easy to adapt: data does not need to be completely rewritten even if it changes.
  • Easy to extend: The code architecture is carefully designed to support future extension of core functionality.
  • Easy to debug: When something goes wrong, the code gives clear information.

readability

  • Neat code, consistent coding style.
  • Code comments are clear and unambiguous.

Here are some general rules for naming variables and functions

  • Variable names should be changed to nouns, as incarperson.
  • Function names should start with a verb, such as:getName(), a function that returns a Boolean value usually begins withisNumber().
  • Make logical names for both variables and functions, and use descriptive and intuitive words as much as possible, but not too redundant.
  • Variables, functions, and methods should start with a lowercase letter and use camelCase. Constant values should be all uppercase and underlined, for exampleREQUEST_TIMEOUT.

Loose coupling

  • Decoupling HTML/CSS/JavaScript.
  • Use external JS files, and external CSS files, not HTML.

Coding conventions

  • Do not add properties or methods to instances or stereotypes dynamically.
  • Do not redefine existing methods.

Global variables are not declared

  • Instead of arbitrarily defining global variable values, you can use a “namespace” design that wraps multiple variable values together.

  • Use let and const instead of var.

performance

Avoid global lookup

  • Refer to the same object more than once, and try to keep references to it in local scope. The longer the chain search, the more time it takes.

Optimizing element interaction

  • When updating a large number of DOM values, you should create a fragment in advance and use itcreateDocumentFragment()innerHTMLChange it once.
  • Use event delegates when a large number of elements are bound to the same event.

Other optimization

  • Use native methods as much as possible. Native is low-level and therefore fast.
  • Switch statements are faster than if statements.
  • Bit manipulation is fast.

The deployment of

  • Code compression confusion.
  • HTTP compression.
  • Remove unused code and features, tree shaker optimization.

Chapter 4 – Variables, Scopes, and Memory

The scope chain

Identifier resolution at code execution is done by searching identifier names down the scope chain. If no value is found in the current scope, it is searched in the upper scope until the global scope is found. The chain formed by the search is called the scope chain.

The garbage collection

The most common JavaScript garbage collection strategy is mark-and-sweep. When a variable is entered into a context, such as declaring a variable inside a function, the variable is marked as existing in the context; Variables are also marked out of context when they are out of context. It is then removed during garbage collection.

performance

The garbage collection program runs periodically. If a lot of variables are allocated in memory, there can be a performance penalty, so scheduling garbage collection is important. The detection mechanism depends on the browser, but is basically based on the size and number of allocated objects.

Chapter 7 – Iterators and Generators

The iterator

Any object that implements the Iterator interface can be used as an Iterator. The Iterator interface is mainly used for… Of consumption.

The native implementation includes Array, Map, Set, String, TypedArray, arguments, NodeList, and can be used directly.

let list = ["a"."b"."c"];
for (let item of list) {
  console.log(item);
}
// a
// b
// c
Copy the code

Iterator traversal process is: every call next method, will return the data structure of the current members of the information, return an object contains the value and the done two attributes. Where, the value attribute is the value of the current member, and the done attribute is a Boolean value indicating whether the traversal is complete.

let listr = list[Symbol.iterator](); // Call the inner iteration function
console.log(listr.next()); // { value: 'a', done: false }
console.log(listr.next()); // { value: 'b', done: false }
console.log(listr.next()); // { value: 'c', done: false }
console.log(listr.next()); // { value: undefined, done: true }
Copy the code

Native objects do not deploy the Iterator interface, but you can of course deploy it manually (the code below is moot, just for demonstration purposes).

let list = {
  a: "a".b: "b".c: "c".Manually deploy the Iterator interface
  [Symbol.iterator]() {
    // Use closures to store all values and the number of iterations
    let keys = Object.values(this);
    let count = 0;
    return {
      next() {
        // If this iteration has a value, the count is increased by 1, and done is false to continue the next iteration.
        if (keys[count]) {
          return {
            value: keys[count++],
            done: false}; }// If this iteration has no value, done is true to end the iteration.
        else {
          return {
            value: undefined.done: true}; }}}; }};for (let i of list) {
  console.log(i);
}
// a
// b
// c

// Manual invocation is also possible as native.
let listr = list[Symbol.iterator]();
console.log(listr.next()); // { value: 'a', done: false }
console.log(listr.next()); // { value: 'b', done: false }
console.log(listr.next()); // { value: 'c', done: false }
console.log(listr.next()); // { value: undefined, done: true }
Copy the code

The generator

A generator is a function in the form of a function whose name is preceded by an asterisk (*) to indicate that it is a generator. Generators can be defined wherever functions can be defined. Calling a generator produces a generator object that starts in a suspended state. Execution starts after the first call to the next method.

function* generatorFn() {
  return "generator";
}

let generator = generatorFn();
console.log(generator); // generatorFn <suspended>
console.log(generator.next()); // { value: 'generator', done: true }
Copy the code

Interrupt execution by yield; The yield keyword is a bit like an intermediate return statement for a function. The value it generates will appear on the object returned by the yield method, and any generator function that exits with the return keyword will be in the done true state.

function* generatorFn() {
  yield 1;
  yield 2;
  return 3;
}

let generator = generatorFn();
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: true }
Copy the code

Yield * really just serializes an iterable into a series of values that can be produced individually, so it’s no different than putting yield in a loop.

function* generatorFn1() {
  yield* [1.2.3];
}

for (let item of generatorFn1()) {
  console.log(item);
}

// = equivalent
function* generatorFn2() {
  for (let i = 1; i < 4; i++) {
    yieldi; }}for (let item of generatorFn2()) {
  console.log(item);
}
Copy the code

Chapter 8 – Objects, Classes, and Object-oriented Programming

Syntactic shorthand

When adding a variable to an object, if the property name is the same as the variable name. You can just write the attribute name.

let name = "lian";
let person = {
  name: name,
};

/ / is equivalent to
let name = "lian";
let person = {
  name,
};
Copy the code

A computable property, a computable property is a property value of an object that can be an expression.

let key = "name";
let person = {};
person[key] = key;

/ / is equivalent to
let key = "name";
let person = {
  [key]: key,
};
Copy the code

Short method name.

let person = {
  sayName: function (name) {
    console.log(name); }};/ / is equivalent to
let person = {
  sayName(name) {
    console.log(name); }};Copy the code

The constructor

The constructor

Constructors are defined no differently than ordinary functions. The difference is that the constructor is executed using the new operator.

function Person() {}

Person();
let person = new Person(); // Constructors usually start with a capital letter
Copy the code

To create an instance of Person, use the new operator. Calling the constructor in this way does the following:

  • Create a new object in memory.
  • The [[Prototype]] feature inside this new objectThe assigned valueIs the prototype property of the constructor.
  • This inside the constructorThe assigned valueFor this new object.
  • Execute the code inside the constructor.
  • 5. If the constructor returns a non-empty object, the modified object is returned. Otherwise: Returns the newly created object.
The prototype pattern

Whenever a function is created, a Prototype attribute (pointing to the prototype object) is created for the function according to specific rules. By default, all stereotype objects automatically get a property called constructor that refers back to the constructor associated with them.

Each time an instance is created, the __proto__ (a reference to hidden [[Prototype]]) attribute is exposed on the instance object pointing back to the constructor’s Prototype. Understand that there is a direct connection between the instance and the constructor stereotype, but not between the instance and the constructor.

// After the declaration, the function has a prototype object associated with it.
function Person() {
  this.name = "lian";
}
console.log(Person.prototype);
Copy the code
// As mentioned earlier: the constructor has a prototype property;
// References its prototype object, which also has a constructor property that references the constructor,
// In other words, both project references
console.log(Person.prototype.constructor === Person); // true
Copy the code
// Instance links to Prototype objects via __proto__ (hides references to [[Prototype]])
// The instance is not directly related to the constructor, but to the prototype object
let person = new Person();
console.log(person.__proto__ === Person.prototype); // true
console.log(person.__proto__.constructor === Person.prototype.constructor); // true
Copy the code

The relationship between constructor, prototype, constructor, and __proto__ is shown below.

Prototype inheritance

The prototype chain is defined as the main inheritance mode. Review the relationship between constructors, stereotypes, and instances: Each constructor has a stereotype object, the stereotype has a property that points back to the constructor, and the instance has an internal pointer to the stereotype.

What if the stereotype is an instance of another type? That means that the stereotype itself has an internal pointer to another stereotype, which in turn has a pointer to another constructor, thus creating a chain of stereotypes between the instance and the stereotype.

function SuperType() {
  this.superProperty = true;
}
SuperType.prototype.getSuperValue = function () {
  return this.superProperty;
};

function SubType() {
  this.subProperty = false;
}

// The prototype of SubType is assigned to an instance of SuperType.
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
  return this.subProperty;
};

let instance = new SubType();

// __proto__ refers to the instance prototype, and the prototype is assigned "SuperType instance".
console.log(instance.__proto__);
// Further down __proto__ points to the prototype of "SuperType instance".
console.log(instance.__proto__.__proto__);
// Continuing below, the prototype's "constructor" points to the constructor
console.log(instance.__proto__.__proto__.constructor === SuperType); // true

// The getSubValue and getSuperValue methods can be found on this chain.
console.log(instance.getSubValue()); // false
console.log(instance.getSuperValue()); // true
Copy the code

The stereotype chain extends the stereotype search mechanism so that when you read a property on an instance, you first search for that property on the instance. If not, the search continues for the prototype of the instance, and after inheritance through the prototype chain, the search continues upward, searching for the prototype’s prototype.

class

Think of classes as special functions

Classes are at bottom just syntactic sugar for constructors, but can only be called with new.

class Person {}

let person = new Person();

console.log(typeof Person); // function
console.log(Person.prototype.constructor === Person); // true
console.log(person.__proto__ === Person.prototype); // true
console.log(person.__proto__.constructor === Person.prototype.constructor); // true
Copy the code
Class inheritance

ES6 classes support single-class inheritance, using the extends keyword. In derived classes you can refer to their archetypes through the super keyword.

class Vehicle {
  constructor() {
    this.hasEngine = true;
  }
  run() {
    console.log("... run");
  }
  static identify() {
    console.log("Vehicle"); }}// static declares static methods that can be called directly on the class.
Vehicle.identify(); // "Vehicle"

Bus extends the Vehicle class.
class Bus extends Vehicle {
  constructor() {
    // Use super in the constructor to call the superclass constructor and assign the returned instance to this.
    super(a);console.log(this);
  }
  Static methods defined on classes from which static methods can be called via super.
  static identify() {
    super.identify();
  }
}

Bus.identify(); // "Vehicle"

let bus = new Bus();
bus.run(); / /... run

// The inheritance method is the same as that of the constructor, except that the syntax level is more semantic
console.log(bus.__proto__.constructor === Bus); // true
console.log(bus.__proto__.__proto__.constructor === Vehicle); //true
console.log(bus.__proto__.__proto__ === Vehicle.prototype); //true
console.log(bus instanceof Vehicle); // true
console.log(bus instanceof Bus); // true
Copy the code

Chapter 9 – Agency and Reflection

The agent

All operations on the proxy object are applied to the target object.

const target = {
  id: "target"};const proxy = new Proxy(target, {});

console.log(proxy.id); // target
console.log(target.id); // target
Copy the code

Simple proxy objects don’t solve anything, so you can configure a catcher in a proxy. Whenever an operation is performed on a proxy object, the default behavior can be modified by calling the catcher when the operation reaches the target object.

const target = {
  id: "target"};const proxy = new Proxy(target, {
  get(target, property, receiver) {
    return target[property] + "...";
  },
  set(target, property, value, receiver) {
    return(target[property] = value); }});console.log(proxy.id); // target...
console.log(target.id); // target
Copy the code

reflection

While the default behavior can be redefined, some catchers are not that simple. This can then be created using a method of the same name on the global Reflect object that encapsulates the original behavior.

This means that while the default Proxy behavior has been redefined, the original default behavior on Reflect can be called within the redefined default behavior. It is equivalent to doing a forwarding, which can do some other operations and ensure the integrity of the original behavior.

Proxy intercepts the default behavior of the object
// include all methods on Proxy, no matter how Proxy is modified.
const obj = { name: "l".location: { city: "beijing"}};const proxyObj = new Proxy(obj, {
  get(target, property, receiver) {
    console.log(`getting ${property}`);
    return Reflect.get(target, property, receiver);
  },
  set(target, property, value, receiver) {
    console.log(`setting ${property}.${value}`);
    return Reflect.set(target, property, value, receiver); }}); proxyObj.name; proxyObj.name ="lian";
proxyObj.location.city = "beijing haidian"; // The get of location is triggered only once, and the hierarchy object cannot respond

// getting name
// setting name, lian
// getting location
Copy the code

Chapter 11 – Term Contracts and Asynchronous Functions

Futures (Promise)

Promise has three states and stays in one of them all the time.

  • To be determined (pending)
  • This is a big pity, which is also called resolved.
  • Refused to (rejected)

When a Promise is created, it is in a pending state.

let p1 = new Promise(() = > {});
console.log(p1); // Promise <pending>
Copy the code

The argument to a Promise is that a function accepts two arguments, usually named resolve and Reject.

When the resolve function is called, the state switches to fulfilled and the promise.Prototype.then () method is executed.

let p2 = new Promise((resolve, reject) = > {
  resolve(1);
}).then((result) = > {
  console.log(result); / / 1
});
console.log(p2); // Promise <fulfilled>
Copy the code

When the reject function is called, the state switches to Rejected and the promise.prototype.catch () method is executed.

let p3 = new Promise((resolve, reject) = > {
  reject(2);
}).catch((error) = > {
  console.log(error); / / 2
});
console.log(p3); // Promise <rejected>
Copy the code

An asynchronous function

Declare an asynchronous function using async. If an asynchronous function does not contain the await keyword, it performs just like a normal function. Return a fulfilled Promise after execution.

function foo() {
  return 1;
}

async function fooAsync() {
  return 2;
}

console.log(foo()); / / 1
console.log(fooAsync()); // Promise <fulfilled> 2

fooAsync().then((result) = > {
  console.log(result); / / 2
});
Copy the code

The anticipation behind await is an instance of Promise, which will be fulfilled only when the instance returns the fulfilled state. If not, it will also be regarded as a fulfilled Promise.

async function foo() {
  console.log(2);
  console.log(await 6);
  console.log(7);
}

async function bar() {
  console.log(4);
  console.log(await Promise.resolve(8));
  console.log(9);
}

console.log(1);
foo();
console.log(3);
bar();
console.log(5);

/ / 123456789
Copy the code

Chapter 26 – Modules

IIFE

IIFE(Immediately Ivoked Function Expression) encapsulates module definitions in anonymous functions using Function scope and immediate Function Expression.

let Foo = (function () {
  // Code for the private Foo module
  var bar = "bar...";
  return{ bar, }; }) ();console.log(Foo.bar); // bar...
Copy the code

CJS

Commonjs (CJS) is the standard module used by NodeJS.

//./add.js -- Defines the module
function add(a, b) {
  return a + b;
}
module.exports = add;
Copy the code
//./index.js -- use modules
const add = require("./add");
console.log(add(1.2)); / / 3
Copy the code

AMD

Asynchronous Module Definition (AMD) is the standard Module used by RequireJS. It is a completely browse-specific modular Definition.

//./add.js -- Defines the module
define(function () {
  return function add(a, b) {
    return a + b;
  };
});
Copy the code
<! -- index.html -- use the module -->
<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
  <script>
    require(["./add"].function (add) {
      console.log(add(1.2)); / / 3
    });
  </script>
</body>
Copy the code

UMD

UMD(Universal Module Definition), also known as the Universal Module Definition, is intended to be compatible with CJS and AMD specifications. The principle is to return different module definitions for different environments.

(function (global, factory) {
  if (typeof exports= = ="object" && typeof module! = =undefined) {
    // cjs
    module.exports = factory();
  } else if (typeof define === "function" && define.amd) {
    // amd
    define(factory);
  } else {
    // global
    global = typeofglobalThis ! = ="undefined" ? globalThis : global || self;
    global.add = factory();
  }
})(this.function () {
  return function add(a, b) {
    return a + b;
  };
});
Copy the code

ESM

ESM(ES Module) : ES6 introduces a set of native Module specifications.

export default function add(a, b) {
  return a + b;
}
Copy the code
import add from "./add.js";
console.log(add(1.2)); / / 3
Copy the code