返回
JavaScript中的那些鲜为人知的骚操作,你都知道吗?
前端
2023-12-19 00:13:21
1. 数组去重
正常我们实现数组去重大多都是通过双层遍历或者indexOf的方式。
// 双层for循环去重
function unique1(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
let isUnique = true;
for (let j = 0; j < result.length; j++) {
if (arr[i] === result[j]) {
isUnique = false;
break;
}
}
if (isUnique) {
result.push(arr[i]);
}
}
return result;
}
// 利用indexOf去重
function unique2(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
但其实有一种更简单的方式:利用Array.from与set去重
function unique3(arr) {
return Array.from(new Set(arr));
}
这种代码的实现原理是:利用Set的数据结构,Set可以自动去重,然后利用Array.from()方法将Set转换为数组。
2. 函数柯里化
函数柯里化是指将一个函数拆分成多个子函数,每个子函数都接受一个参数,并将结果传递给下一个子函数,最终得到最终结果。
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
} else {
return (...rest) => curried(...args, ...rest);
}
};
}
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
curriedSum(1)(2)(3); // 6
curriedSum(1, 2)(3); // 6
curriedSum(1, 2, 3); // 6
函数柯里化的好处是可以将一个复杂函数拆分成多个简单的函数,方便代码的复用和维护。
3. 事件委托
事件委托是指将事件监听器注册到父元素上,而不是子元素上。当子元素触发事件时,事件会向上冒泡到父元素,父元素的事件监听器就会被触发。
const parent = document.getElementById('parent');
parent.addEventListener('click', (event) => {
// 事件委托,可以处理子元素的点击事件
console.log(event.target);
});
事件委托的好处是可以减少事件监听器的数量,提高代码的性能。
4. 深拷贝
深拷贝是指将一个对象的所有属性和子属性都复制一份,而浅拷贝只复制一层。
// 浅拷贝
const obj1 = {
name: 'John',
age: 20,
address: {
street: 'Main Street',
city: 'New York',
},
};
const obj2 = { ...obj1 };
obj2.address.street = 'Wall Street';
console.log(obj1); // { name: 'John', age: 20, address: { street: 'Wall Street', city: 'New York' } }
console.log(obj2); // { name: 'John', age: 20, address: { street: 'Wall Street', city: 'New York' } }
// 深拷贝
const obj1 = {
name: 'John',
age: 20,
address: {
street: 'Main Street',
city: 'New York',
},
};
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.address.street = 'Wall Street';
console.log(obj1); // { name: 'John', age: 20, address: { street: 'Main Street', city: 'New York' } }
console.log(obj2); // { name: 'John', age: 20, address: { street: 'Wall Street', city: 'New York' } }
深拷贝的好处是可以保证两个对象完全独立,互不影响。
5. 防抖
防抖是指在事件连续触发的情况下,只执行一次函数。
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
};
const input = document.getElementById('input');
const debouncedInput = debounce((event) => {
console.log(event.target.value);
}, 500);
input.addEventListener('input', debouncedInput);
防抖的好处是可以防止函数被频繁调用,提高代码的性能。
6. 节流
节流是指在一定时间内只执行一次函数。
const throttle = (fn, delay) => {
let lastTime = 0;
return (...args) => {
const now = Date.now();
if (now - lastTime >= delay) {
fn(...args);
lastTime = now;
}
};
};
const scrollHandler = throttle((event) => {
console.log(window.scrollY);
}, 100);
window.addEventListener('scroll', scrollHandler);
节流的好处是可以防止函数被频繁调用,提高代码的性能。
7. 箭头函数
箭头函数是ES6中引入的新语法,它可以替代传统的函数表达式。
// 传统函数表达式
const sum = function(a, b) {
return a + b;
};
// 箭头函数
const sum = (a, b) => a + b;
箭头函数的好处是语法更简洁,而且可以自动绑定this。
8. Promise
Promise是ES6中引入的新语法,它可以表示一个异步操作的结果。
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve('Hello, world!');
}, 1000);
});
promise.then((result) => {
console.log(result); // Hello, world!
});
Promise的好处是可以让代码更加易读和可维护。
9. 原型链
原型链是JavaScript中一个重要的概念,它可以实现继承。
// 父类
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 子类
class Student extends Person {
constructor(name, age, school) {
super(name, age);
this.school = school;
}
study() {
console.log(`I am studying at ${this.school}.`);
}
}
// 创建一个学生对象
const student = new Student('John', 20, 'Harvard University');
// 调用greet方法
student.greet(); // Hello, my name is John