Note that although a constant in JavaScript must always name the same value, you can change the content of the value that it names. This isn’t a useful distinction for simple types like numbers or booleans, but consider an object:
switch (expression) {
case choice1:
// run this code
break;
case choice2:
// run this code instead
break;
// include as many cases as you like
default:
// actually, just run this code
break;
}
WIndow代表加载页面的浏览器窗口,The window is the browser tab that a web page is loaded into;this is represented in JavaScript by the Window object. Using methods available on this object you can do things like return the window’s size (see Window.innerWidth and Window.innerHeight), manipulate the document loaded into that window, store data specific to that document on the client-side (for example using a local database or other storage mechanism), attach an event handler to the current window, and more.
Navigator代表浏览器The navigator represents the state and identity of the browser (i.e. the user-agent) as it exists on the web. In JavaScript, this is represented by the Navigator object. You can use this object to retrieve things like the user’s preferred language, a media stream from the user’s webcam, etc.
Document则为实际加载的页面The document (represented by the DOM in browsers) is the actual page loaded into the window, and is represented in JavaScript by the Document object. You can use this object to return and manipulate information on the HTML and CSS that comprises the document, for example get a reference to an element in the DOM, change its text content, apply new styles to it, create new elements and add them to the current element as children, or even delete it altogether.
async function fetchProducts() {
try {
// after this line, our function will wait for the `fetch()` call to be settled
// the `fetch()` call will either return a Response or throw an error
const response = await fetch(
"https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json",
);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
// after this line, our function will wait for the `response.json()` call to be settled
// the `response.json()` call will either return the parsed JSON object or throw an error
const data = await response.json();
console.log(data[0].name);
} catch (error) {
console.error(`Could not get products: ${error}`);
}
}
fetchProducts();
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
reject(new Error("Alarm delay must not be negative"));
return;
}
setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
Worker
为Javascript提供了多线程的可能。
单独创建一个文件作为另一个线程的内容
主线程与worker采用message沟通,且worker无法访问DOM,以及主线程的任何内容
eg.main.js// Create a new worker, giving it the code in "generate.js" const worker = new Worker("./generate.js"); // When the user clicks "Generate primes", send a message to the worker. // The message command is "generate", and the message also contains "quota", // which is the number of primes to generate. document.querySelector("#generate").addEventListener("click", () => { const quota = document.querySelector("#quota").value; worker.postMessage({ command: "generate", quota, }); }); // When the worker sends a message back to the main thread, // update the output box with a message for the user, including the number of // primes that were generated, taken from the message data. worker.addEventListener("message", (message) => { document.querySelector("#output").textContent = `Finished generating ${message.data} primes!`; }); document.querySelector("#reload").addEventListener("click", () => { document.querySelector("#user-input").value = 'Try typing in here immediately after pressing "Generate primes"'; document.location.reload(); });
worker.js
// Listen for messages from the main thread.
// If the message command is "generate", call `generatePrimes()`
addEventListener("message", (message) => {
if (message.data.command === "generate") {
generatePrimes(message.data.quota);
}
});
// Generate primes (very inefficiently)
function generatePrimes(quota) {
function isPrime(n) {
for (let c = 2; c <= Math.sqrt(n); ++c) {
if (n % c === 0) {
return false;
}
}
return true;
}
const primes = [];
const maximum = 1000000;
while (primes.length < quota) {
const candidate = Math.floor(Math.random() * (maximum + 1));
if (isPrime(candidate)) {
primes.push(candidate);
}
}
// When we have finished, send a message to the main thread,
// including the number of primes we generated.
postMessage(primes.length);
}
// Call `fetch()`, passing in the URL.
fetch(url)
// fetch() returns a promise. When we have received a response from the server,
// the promise's `then()` handler is called with the response.
.then((response) => {
// Our handler throws an error if the request did not succeed.
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
// Otherwise (if the response succeeded), our handler fetches the response
// as text by calling response.text(), and immediately returns the promise
// returned by `response.text()`.
return response.text();
})
// When response.text() has succeeded, the `then()` handler is called with
// the text, and we copy it into the `poemDisplay` box.
.then((text) => {
poemDisplay.textContent = text;
})
// Catch any errors that might happen, and display a message
// in the `poemDisplay` box.
.catch((error) => {
poemDisplay.textContent = `Could not fetch verse: ${error}`;
});
Whether a request can be made cross-origin or not is determined by the value of the RequestInit.mode option. This may take one of three values: cors, same-origin, or no-cors.
For fetch requests the default value of mode is cors, meaning that if the request is cross-origin then it will use the Cross-Origin Resource Sharing (CORS) mechanism. This means that:
if the request is a simple request, then the request will always be sent, but the server must respond with the correct Access-Control-Allow-Origin header or the browser will not share the response with the caller.
if the request is not a simple request, then the browser will send a preflighted request to check that the server understands CORS and allows the request, and the real request will not be sent unless the server responds to the preflighted request with the appropriate CORS headers.
Setting mode to same-origin disallows cross-origin requests completely.
Setting mode to no-cors disables CORS for cross-origin requests. This restricts the headers that may be set, and restricts methods to GET, HEAD, and POST. The response is opaque, meaning that its headers and body are not available to JavaScript. Most of the time a website should not use no-cors: the main application of it is for certain service worker use cases.
Add an event listener to its load event, which fires when the response has completed successfully. In the listener we call initialize() with the data.
Add an event listener to its error event, which fires when the request encounters an error
Send the request.
We also have to wrap the whole thing in the try…catch block, to handle any errors thrown by open() or send().
Hopefully you think the Fetch API is an improvement over this. In particular, see how we have to handle errors in two different places.
// global scope
const e = 10;
function sum(a) {
return function (b) {
return function (c) {
// outer functions scope
return function (d) {
// local scope
return a + b + c + d + e;
};
};
};
}
console.log(sum(1)(2)(3)(4)); // 20
// global scope
const e = 10;
function sum(a) {
return function sum2(b) {
return function sum3(c) {
// outer functions scope
return function sum4(d) {
// local scope
return a + b + c + d + e;
};
};
};
}
const sum2 = sum(1);
const sum3 = sum2(2);
const sum4 = sum3(3);
const result = sum4(4);
console.log(result); // 20
常见错误:var定义变量不会对大括号作用域生效,故所有item共享一个作用域,后面内容被覆盖
function showHelp(help) {
document.getElementById("help").textContent = help;
}
function setupHelp() {
var helpText = [
{ id: "email", help: "Your email address" },
{ id: "name", help: "Your full name" },
{ id: "age", help: "Your age (you must be over 16)" },
];
for (var i = 0; i < helpText.length; i++) {
// Culprit is the use of `var` on this line
var item = helpText[i];
document.getElementById(item.id).onfocus = function () {
showHelp(item.help);
};
}
}
setupHelp();
解决方法1:每个函数创建新的闭包,变量被复制到新闭包作用域中使用
function showHelp(help) {
document.getElementById("help").textContent = help;
}
function makeHelpCallback(help) {
return function () {
showHelp(help);
};
}
function setupHelp() {
var helpText = [
{ id: "email", help: "Your email address" },
{ id: "name", help: "Your full name" },
{ id: "age", help: "Your age (you must be over 16)" },
];
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
}
}
setupHelp();
解决方法2.使用let定义变量(对大括号生效)
function showHelp(help) {
document.getElementById("help").textContent = help;
}
function setupHelp() {
const helpText = [
{ id: "email", help: "Your email address" },
{ id: "name", help: "Your full name" },
{ id: "age", help: "Your age (you must be over 16)" },
];
for (let i = 0; i < helpText.length; i++) {
const item = helpText[i];
document.getElementById(item.id).onfocus = () => {
showHelp(item.help);
};
}
}
setupHelp();
function create(id, parent, width, height) {
...
}
function createReportList(wrapperId) {
...
}
export { create, createReportList };
或者
export const name = "square";
export function draw(ctx, length, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, length, length);
return { length, x, y, color };
}
主js文件(直接嵌入html的)通过import导入
eg.
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
特性:
默认导出
一个模块文件只能存在一个
eg.
export default function (ctx) {
// ...
}
导入:
import { default as randomSquare } from "./modules/square.js";
或者
import randomSquare from "./modules/square.js";
导入与导出的重命名
eg.
// module.js 中
export { function1 as newFunctionName, function2 as anotherNewFunctionName };
// main.js 中
import { newFunctionName, anotherNewFunctionName } from "/modules/module.js";
// module.js 中
export { function1, function2 };
// main.js 中
import {
function1 as newFunctionName,
function2 as anotherNewFunctionName,
} from "./modules/module.js";
模块对象
将模块功能导入到一个模块功能对象中
eg.
import * as Module from "/modules/module.js";
使用时
Module.function1();
Module.function2();
合并模块
eg.
shape.js
export { Square } from "./shapes/square.js";
export { Triangle } from "./shapes/triangle.js";
export { Circle } from "./shapes/circle.js";
main.js
import { Square, Circle, Triangle } from "./modules/shapes.js";
// 裸模块名称作为模块标识符
import { name as squareNameOne } from "shapes";
import { name as squareNameTwo } from "shapes/square";
// 重新映射一个 URL 到另一个 URL
import { name as squareNameThree } from "https://example.com/shapes/square.js";
// 重新映射一个 URL 作为前缀 ( https://example.com/shapes/)
import { name as squareNameFour } from "https://example.com/shapes/moduleshapes/square.js";