JavaScript-技巧积累

fetch 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
useEffect(() => {
const fetchData = async () => {
try {
let response = await fetch("http://127.0.0.1:8112/homepage/music/list");
let jsonData = await response.json();
if (jsonData && jsonData.length > 0) {
setSongList(jsonData);
console.log(jsonData[curSongIndex]);
}
} catch (error) {
console.error("Fetch error: ", error);
}
};

fetchData();
}, []); // Waitting for implement, when to update list??

需要注意两点:

  1. fetch() 的返回值是一个 Promise 异步对象
  2. response.json() 的返回值也是一个 Promise 异步对象
    都需要用 await 处理.

抛出自定义的异常

使用 throw 语句, 出的异常可以是任何类型的值, 但通常是一个 Error 对象. throw 语句通常与 try...catch 语句结合使用, 以捕获和处理异常.

如:

1
2
3
4
5
6
7
8
9
10
11
12
function validateNumber(num) {
if (isNaN(num)) {
throw new Error("The provided argument is not a number.");
}
return true;
}

try {
validateNumber("not a number");
} catch (e) {
console.error(e.message); // 输出: The provided argument is not a number.
}

字符串跨行

使用模板字符串:

1
2
3
let multiLineString = `This is the first line.
This is the second line.
This is the third line.`;

用 setInterval 创建定时器定期执行函数

setInterval 是 JavaScript 提供的一个函数, 用于在指定的时间间隔 (以毫秒为单位) 重复执行一个函数或一段代码.

语法为:

1
setInterval(function, delay, arg1, arg2, ...)

其还会返回一个 id 值, 可用于 clearInternal 函数来清除周期执行, 如:

1
2
3
4
5
6
7
8
9
10
11
12
13
function displayTime() {
const now = new Date();
document.getElementById('time').innerText = now.toLocaleTimeString();
}

// 每秒运行 displayTime 函数一次
const intervalID = setInterval(displayTime, 1000);

// 运行 10 秒后停止显示时间
setTimeout(() => {
clearInterval(intervalID);
document.getElementById('time').innerText = '停止显示时间';
}, 10000);

使用展开语法复制对象

通过写出所有成员的复制方法:

1
2
3
4
5
setPerson({
firstName: e.target.value, // 从 input 中获取新的 first name
lastName: person.lastName,
email: person.email
});

等价于下面展开语法的复制方法:

1
2
3
4
setPerson({
...person, // 复制上一个 person 中的所有字段
firstName: e.target.value // 但是覆盖 firstName 字段
});

注意这种语法只会复制一层 (如果是嵌套对象要注意).

利用 setTimeout 函数来延迟某些操作

setTimeout 是浏览器内置的 API, 其允许设置一个定时器, 当定时器到期时, 指定的代码或函数将被执行, 基本语法:

1
setTimeout(function, delay, param1, param2, ...);
  • function: 要执行的函数
  • delay: 以毫秒为单位的时间, 表示延迟多长时间后执行函数
  • param1, param2, ...: (可选) 传递给函数的参数

示例:

1
2
3
setTimeout(() => {
console.log('Arrow function after 1 second');
}, 1000);

也可以在定时器到期前取消它, 用 clearTimeout 函数, setTimeout 会返回一个定时器 ID, 这个 ID 可以用于取消定时器:

1
2
3
4
5
let timerId = setTimeout(() => {
console.log('This will not be shown');
}, 5000);

clearTimeout(timerId); // 定时器被取消,回调函数不会被执行

数组的遍历

用数组的 forEach() 方法:

1
2
3
4
let list = ['hello', 'world'];
list.forEach((elem) => {
console.log(elem)
})

数组的展开

... 语法将一个数组内所有的元素拆分出来:

1
2
3
4
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // Output: [1, 2, 3, 4]

数组的扩容

JavaScript 中的数组是动态扩容的, 也就是不需要一开始就分配固定的内存大小, 如:

1
2
3
4
5
6
7
let myArray = [1, 2, 3];
console.log(myArray.length); // Output: 3

// 向数组添加新元素
myArray[5] = 6;
console.log(myArray.length); // Output: 6
console.log(myArray); // Output: [1, 2, 3, undefined, undefined, 6]

创建数组的副本

slice 方法:

1
2
let hello = [1, 2, 3, 4];
world = hello.slice(0,2); // world = [1,2,3]

若不传递参数, 则复制整个数组.

匿名函数

() => 会隐式返回 => 之后的表达式, 因此可以省略 return 语句, 如:

1
2
3
const listItems = chemists.map(person =>
<li>...</li> // 隐式地返回!
);

但如果 => 之后是花括号 {, 则必须用 return 来指定:

1
2
3
const listItems = chemists.map(person => { // 花括号
return <li>...</li>;
});

函数的解构赋值

解构赋值是指, 从对象中提取属性并赋值给变量, 如:

1
2
3
4
5
6
7
8
9
10
11
const person = { name: 'Alice', age: 25 };

// 不使用解构赋值
const name = person.name;
const age = person.age;

// 使用解构赋值
const { name, age } = person;

console.log(name); // 'Alice'
console.log(age); // 25

应用到函数中, 如:

1
2
3
4
5
6
7
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}

此时调用该函数, 传入一个对象, 就会自动解构.

其对应的非解构写法为:

1
2
3
4
5
6
7
8
9
10
function MyButton(props) {
const count = props.count;
const onClick = props.onClick;

return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}

Array 的 filter 方法

filter() 方法返回一个新数组, 匿名函数的结果为 true, 则将元素添加进数组. 如:

1
2
3
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // 输出: [2, 4, 6]

Array 的 map 方法

map() 方法返回一个新数组, 其结果是对原数组中的每个元素调用一个提供的函数后的返回值.

如:

1
2
3
4
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);

console.log(doubled); // [2, 4, 6, 8]

相当于原数组乘 2.

也可以访问索引:

1
2
3
4
const numbers = [1, 2, 3, 4];
const withIndex = numbers.map((num, index) => num * index);

console.log(withIndex); // [0, 2, 6, 12]

简单创建模块文件

使用 ES6 模块语法, 如:

1
2
3
4
5
// utils/hello.js

export function hello() {
console.log("Hello, world!");
}

若想导入这个包内的 hello() 函数, 如:

1
2
3
import { hello } from "./utils/hello.js"

hello()

export 的两种主要用法

  1. 具名导出, Named Exports, 允许导出多个值
  2. 默认导出, Default Export, 每个模块只能有一个默认导出

Named Exports

在声明时使用 export 关键字, 如:

1
2
3
4
5
6
7
// math.js

export const pi = 3.14159;

export function add(a, b) {
return a + b;
}

此时在另一个文件中导入:

1
2
3
4
import { pi, add } from "./math.js"

console.log(pi); // 3.14159
console.log(add(2, 3)); // 5

Default Export

1
2
3
4
5
// greet.js

export default function hello() {
console.log("Hello, world!");
}

此时可以用任意名称导入:

1
2
3
4
5
// main.js

import greet from './greet.js';

greet(); // Hello, world!

组合使用

1
2
3
4
5
6
7
8
9
10
11
// utilities.js

export const pi = 3.14159;

export default function greet() {
console.log("Hello, world!");
}

export function add(a, b) {
return a + b;
}

此时导入:

1
2
3
4
5
6
7
// main.js

import greet, { pi, add } from './utilities.js';

greet(); // Hello, world!
console.log(pi); // 3.14159
console.log(add(2, 3)); // 5

导入外部包

对于 Node.js, 有两种方法:

  • 使用 CommonJS 模块 require
  • 使用 ES6 模块 import

使用 CommonJS 模块

如:

1
const express = require('express');

使用 ES6 模块

1
import express from 'express';

使用这种方法导入, 需要修改 package.json 文件, 添加 "type": "module" 字段, 告诉 Node.js 该项目使用 ES6 模块. 如:

1
2
3
4
5
6
7
8
9
10
11
{
"name": "your-project-name",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js"
},
"dependencies": {
}
}

包的搜索路径

对于 Node.js 内置的核心模块, 如 fs, path, http 等, 其被编译成 Node.js 的二进制文件中, 并且在运行时由 Node.js 引擎直接加载和使用. 因此不需要考虑搜寻路径.

对于其他模块, 若是单独的文件, 可以用绝对路径或相对路径直接加载.

若导入一个包名, 则会从 node_modules/ 目录下查找.

内插字符串

1
2
const name = "hello";
console.log(`nice to meet you! ${name}`);

JS 中的全局对象

全局对象是 JavaScript 语言内置的, 始终可用, 并且不需要通过任何导入操作即可使用. 而导入包 (模块) 是指从外部文件或库中引入特定的功能或对象, 这通常在模块化编程中使用.

常用的全局对象有:

  • console, 用于输出信息到控制台
  • window, 代表浏览器窗口
  • document, 代表整个 HTML 文档, 用于操作 DOM
  • Math, 提供数学常数和函数
  • Date, 用于处理日期和时间
  • JSON, 用于解析和序列化 JSON 数据
  • Promise, 用于处理异步操作的对象
  • fetch, 用于发起网络请求 (在浏览器环境中)

这里有些命名约定:

  • 全小写通常是方法或函数
  • 首字母大写通常是构造函数或类
  • 全大写通常是常量或固定值

字符打印

JavaScript 中没有内置 printprintf 函数, 其提供 console.log, console.error, console.warn 来输出信息到控制台.

console

console 是一个全局对象, 其提供了一组方法, 用于在浏览器或 Node.js 环境的控制台输出信息.

  • console.log() 用于一般消息输出
  • console.error() 用于错误输出, 不会导致程序中断或退出, 常以红色或带有错误标识的形式显示
  • console.warn() 用于警告输出

document 对象

当在浏览器中打开一个网页时,浏览器会把 HTML 代码解析成一个 DOM(Document Object Model 文档对象模型)树,这个树是由各种 HTML 元素和它们的属性组成的。

在 JavaScript 中,我们可以使用 Document 对象来访问和操作这个 DOM 树。Document 对象是一个表示当前 HTML 文档的对象,它可以让我们使用 JavaScript 来获取和修改 HTML 元素的内容和属性,或者在页面上创建新的元素或节点。

下面是一些 Document 对象中常用的属性和方法:

  • document.getElementById(id):通过 ID 获取指定的元素。
  • document.getElementsByTagName(name):通过标记名获取指定的元素。
  • document.createElement(element):创建一个新的 HTML 元素。
  • document.createTextNode(text):创建一个新的文本节点。
  • document.body:返回页面的 body 元素。
  • document.head:返回页面的 head 元素。
  • document.title:获取或设置页面的标题。

JavaScript-技巧积累
http://example.com/2023/05/14/JavaScript-技巧积累/
作者
Jie
发布于
2023年5月14日
许可协议