1.解构赋值
解构赋值是一种从数组或对象中提取值并将其分配给变量的简洁方法,可以简化代码并提高可读性。对于数组,您可以使用方括号表示,而对于对象,则可以使用大括号表示。
// 解构数组
const [a, b, ...rest] = [1, 2, 3, 4, 5];
// 解构对象
const { name, age, ...info} = { name: 'Stefan', age: 26, role: 'Developer' };
2、展开语法
开发者可以使用展开语法将数组的元素或对象的属性扩展到另一个数组或对象中。这对于制作副本、合并对象和将多个参数传递给函数非常有用。展开语法看起来像三个点 ...,可以按以下方式使用:
// 复制数组
const originalArray = [a, b, c];
const newArray = [...originalArray];
// 合并对象
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj) // {a: 1,b: 2,c: 3,d: 4}
3、柯里化
柯里化是一种将一个多参数函数转换为一系列单参数函数的技术。具体来说,一个接受多个参数的函数被转换为一系列只接受一个参数的函数,每个函数返回另一个接受下一个参数的函数,直到所有参数都被处理完毕。
const multiply = (a) => (b) => a * b;
const multiplyByTwo = multiply(2);
const result = multiplyByTwo(5); // 输出: 10
让我们分析一下这段代码:
1.multiply
函数
const multiply = (a) => (b) => a * b;
multiply
是一个接受一个参数a
的函数。- 它返回一个新的函数,这个新函数接受另一个参数
b
,并返回a * b
的结果。
2. multiplyByTwo
函数
const multiplyByTwo = multiply(2);
- 这里调用了
multiply
函数,并将2
作为参数传入。 multiply(2)
返回了一个新的函数(b) => 2 * b
。multiplyByTwo
现在就是这样一个函数:(b) => 2 * b
。
3. result
变量
const result = multiplyByTwo(5);
- 这里调用了
multiplyByTwo
函数,并将5
作为参数传入。 multiplyByTwo(5)
执行了(b) => 2 * b
这个函数,其中b
是5
。- 结果是
2 * 5
,即10
。
柯里化的体现
multiply
函数接受一个参数a
,并返回一个新的函数,这个新函数接受另一个参数b
,并返回a * b
的结果。- 这种将一个多参数函数转换为一系列单参数函数的过程就是柯里化。
大家也可以看下面这个柯里化的示例再好好品味一下
// 一个普通的三元函数
function add(a, b, c) {
return a + b + c;
}
console.log(add(1, 2, 3)); // 6
// 使用柯里化转换后的函数
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curriedAdd(1)(2)(3)); // 6
4、缓存
缓存技术是一种用于存储昂贵函数调用的结果并避免不必要的重新计算的缓存技术。它可以显著地减慢长期递归或消耗性函数的性能。
const memoizedFibonacci = (function () {
const cache = {};
return function fib(n) {
if (n in cache) return cache[n];
if (n <= 1) return n;
cache[n] = fib(n - 1) + fib(n - 2);
return cache[n];
};
})();
5、Promise 和 Async/Await
Promises 和 Async/Await 对于优雅地处理异步操作并使代码更易读和可维护至关重要。它们有助于避免回调地狱并改善错误处理。
// 使用 Promises
function fetchData() {
return new Promise((resolve, reject) => {
// 异步操作,例如从API获取数据
// 在操作结果的基础上 resolve(data) 或 reject(error)
});
}
// 使用 Async/Await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
6、闭包
闭包(closure)是一个函数以及它所引用环境的组合。创建闭包的常见方式是在一个函数内部创建另一个函数,而该内部函数可以访问外部函数的局部变量,它记住了它们被创建的环境,即使该环境不再可访问。它们有助于创建私有变量和行为封装。
function closure() {
let count = 0;
return function () {
return ++count;
};
}
const counter = closure();
console.log(counter()); // 输出: 1
console.log(counter()); // 输出: 2
7、函数组合
函数组合是将两个或多个函数组合成一个新函数的过程。它鼓励代码重用,有助于逐步创建复杂的转换。
// 定义几个简单的函数
const double = (x) => x * 2;
const square = (x) => x * x;
const increment = (x) => x + 1;
// 函数组合
const compose = (...functions) => (x) =>
functions.reduceRight((acc, fn) => fn(acc), x);
// 使用组合函数
const combinedFunction = compose(double, square, increment);
// 调用组合后的函数
const result = combinedFunction(2); // 步骤: (2 + 1) => 3 -> (3 * 3) => 9 -> (9 * 2) => 18
console.log(result); // 输出: 18
在这个示例中:
-
我们定义了三个简单的函数:
double
(将输入乘以 2)、square
(将输入平方)和increment
(增加 1)。 -
然后,我们定义了一个
compose
函数,它接受多个函数并返回一个新的函数。这个新函数会从右到左依次调用这些函数。 -
最后,我们使用
compose
函数结合了这三个功能,并在输入2
时得到了结果18
。
reduceRight方法:按降序顺序对数组中的所有元素调用指定的回调函数。该回调函数的返回值为累积结果,并且此返回值在下一次调用该回调函数时作为参数提供。
8、代理
代理对象允许您为基本对象操作创建自定义行为。它允许您拦截和修改对象操作。例如,访问属性,分配和调用方法。
const handler = {
get: (target, prop) => {
console.log(Accessing property: ${prop});
return target[prop];
},
};
const targetObj = { name: 'Stefan', age: 26};
const proxyObj = new Proxy(targetObj, handler);
console.log(proxyObj.name); // 输出: Accessing property: name \n Stefan
9、事件委托
事件委托(Event Delegation)是一种优化事件处理的技术,它通过将事件监听器绑定到父元素而不是每个子元素上来提高性能。通过事件冒泡,父元素可以处理所有子元素的事件。它可以减少内存使用量并提高性能,特别是对于大型列表或动态生成的内容。
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
使用事件委托,你可以这样做:
document.getElementById('myList').addEventListener('click', function(event) {
// 检查点击的目标是否是 <li> 元素
if (event.target.tagName === 'LI') {
alert('You clicked on: ' + event.target.textContent);
}
});
10、Web Workers
Web Workers 是一种在浏览器后台运行 JavaScript 代码的技术,它不会阻塞主线程,从而提升页面的响应性能。Web Workers 适用于执行长时间运行的计算任务或处理大量数据的操作。它们对于卸载CPU密集型任务,避免UI挂起并提高性能响应性非常有用。
下面是一个简单的例子,展示如何使用 Web Workers 来计算斐波那契数列:
1. 主文件(index.html
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Workers Example</title>
</head>
<body>
<button id="calculate">Calculate Fibonacci</button>
<p id="result"></p>
<script>
// 监听按钮点击事件
document.getElementById('calculate').addEventListener('click', function() {
// 创建一个新的 Web Worker
const worker = new Worker('fibonacci-worker.js');
// 监听来自 worker 的消息
worker.addEventListener('message', function(event) {
const result = event.data;
document.getElementById('result').textContent = `Fibonacci result: ${result}`;
});
// 向 worker 发送消息
worker.postMessage(40); // 计算第 40 个斐波那契数
});
</script>
</body>
</html>
2. Worker 文件(fibonacci-worker.js
)
// 监听来自主线程的消息
self.addEventListener('message', function(event) {
const n = event.data;
const result = fibonacci(n);
// 向主线程发送结果
self.postMessage(result);
});
// 计算斐波那契数
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
解析
-
主文件 (
index.html
):- 当用户点击按钮时,会创建一个新的 Web Worker 实例。
- 通过
worker.postMessage(40);
向 Worker 发送一个消息,要求计算第 40 个斐波那契数。 - 监听来自 Worker 的消息,并更新页面上的结果。
-
Worker 文件 (
fibonacci-worker.js
):- 监听来自主线程的消息,并获取要计算的斐波那契数的索引。
- 计算斐波那契数,并使用
self.postMessage(result);
将结果发送回主线程。
优点
- 非阻塞:计算斐波那契数列这样的复杂任务在 Web Worker 中运行,不会阻塞主线程,因此页面的 UI 响应不会受到影响。
- 性能优化:适合处理需要长时间运行的任务或大量计算。