1、空值合并赋值操作符 ??=
在 ECMAScript 2021 (ES12) 中作为逻辑赋值运算符提案的一部分正式引入。
只在当前值为 null 或 undefined 时,它才会赋予一个新的值。
user.name = user.name ?? 'Anonymous';
user.name ??= 'Anonymous';
替换掉以下写法
if (user.name === null || user.name === undefined) {
user.name = 'Anonymous';
}
以下写法会替换掉空值和0,false
user.name = user.name || 'Anonymous'; // Replaces '', 0, false too
2、柯里化(Currying)
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。
它可以让你在函数中预设参数,从而使代码更加模块化和可组合。可以解决重复传参的问题,并提高函数功能的适用性。
function curriedAdd(a){
return function(b){
return function(c){
return a + b + c
}
}
}
const applyDiscount = (discount) => (price) => price - (price * discount / 100);
const applyTax = (taxRate) => (price) => price + (price * taxRate / 100);
const twentyPercentOff = applyDiscount(20);
const applyTenPercentTax = applyTax(10);
console.log(twentyPercentOff(100)); // 80
console.log(applyTenPercentTax(100)); // 110
console.log(applyTenPercentTax(twentyPercentOff(100))); // 88
3、解构赋值别名
const apiResponse = {
first_name: 'John',
address: {
city: 'New York',
}
};
const {
first_name: firstName,
address: {
city: hometown,
}
} = apiResponse;
console.log(firstName); // John
console.log(hometown); // New York
4、防抖与节流
核心目的是减少函数执行的频率,从而提高程序的性能和响应速度。
函数防抖关注一定时间连续触发的事件只在最后执行一次(适用于搜索框、窗口resize),而函数节流侧重于一段时间内只执行一次(适用于滚动加载,点击提交)。
防抖是在事件被触发delay秒后再执行回调,如果在这delay秒内又被触发,则重新计时。
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
const search = debounce((query) => {
console.log(`Searching for ${query}`);
// Imagine an API call here
}, 300);
document.getElementById('searchInput').addEventListener('input', (event) => {
search(event.target.value);
});
函数节流的目的,是为了限制函数一段时间内只能执行一次。
function throttle(func, interval) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= interval) { //超过设定时间,才执行
lastCall = now;
func.apply(this, args);
}
};
}
const handleScroll = throttle(() => {
console.log('Scrolled');
// Imagine complex calculations or DOM updates here
}, 300);
window.addEventListener('scroll', handleScroll);
5、memoization 是一种优化技术
如果没有采用记忆化技术,每次调用斐波那契函数都会重复计算相同的值多次,导致时间复杂度呈指数级增长。
const memoize = (fn) => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (!cache[key]) {
cache[key] = fn(...args);
}
return cache[key];
};
};
const fibonacci = memoize((n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(40)); // 102334155
6、代理对象
创建代理,从而能够拦截并重新定义基本操作,如属性查找、赋值、枚举、函数调用等。这为向对象添加自定义行为提供了一种强大的方式。
const user = {
name: 'John',
age: 30
};
const handler = {
get: (target, prop) => {
console.log(`Getting ${prop}`);
return target[prop];
},
set: (target, prop, value) => {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
console.log(`Setting ${prop} to ${value}`);
target[prop] = value;
return true;
}
};
const proxyUser = new Proxy(user, handler); //创建代理
console.log(proxyUser.name); // Getting name, John
proxyUser.age = 35; // Setting age to 35 拦截后重新定义
7、生成器函数function*
生成器函数是通过function*语法定义的特殊函数,它可以在执行过程中暂停,并在稍后恢复执行。yield关键字使生成器函数的执行暂停,并将yield关键字后面的表达式的值返回给生成器的调用者。
function* countAppleSales() {
const saleList = [3, 7, 5];
for (let i = 0; i < saleList.length; i++) {
yield saleList[i];
}
}
const appleStore = countAppleSales();
console.log(appleStore.next()); // { value: 3, done: false }
console.log(appleStore.next()); // { value: 7, done: false }
8、structuredClone 深度克隆对象
结构化克隆会创建对象的深层复制,确保嵌套的对象也被复制。这种方法避免了 JSON.parse(JSON.stringify(obj)) 的限制,如函数, undefined 和循环引用。
const clonedObj = structuredClone(obj);
9、获取数据报错处理
解构失败
const handleData = (data)=> {
const { user } = data;
const { id, name } = user || {};
}
handleData({user: null})
数组
const handleData = (data)=> {
const { userList } = data;
if(Array.isArray(userList)){
const newList = userList.map((item)=> item.name)
}
}
handleData({userList: 123})
对象
const handleData = (data)=> {
const { userList } = data;
const newList = userList.map((item)=> {
const { id, name, age } = item || {};
return `用户id是${id},用户名字是${name},用户年龄是${age}岁了`
});
}
handleData({userList: [null]})