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.
- To create a
String
Type. - Invoke a specific method on the instance.
- 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></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></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 in
car
或person
. - 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 example
REQUEST_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 it
createDocumentFragment()
或innerHTML
Change 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