防抖
用户在短时间内多次触发,只会最终触发一次
const debounce = (fn, interval) => {
// 闭包中缓存timeout返回的key
let timeoutKey = undefined;
// 返回防抖处理后的函数
return (...args) => {
// 清空上次未处理的timeout函数
// 防抖的核心,在间隔时间内,连续调用多次的时候,每次都会取消上次待执行的函数
clearTimeout(timeoutKey);
timeoutKey = setTimeout(() => {
// 别忘了把参数回传给fn
fn(...args);
}, interval)
}
}
节流
用户在短时间内多次触发,会按照设定好的频率触发
const throttle = (fn, interval) => {
// 闭包中缓存timeout返回的key
let timeoutKey = undefined;
// 返回节流处理后的函数
return (...args) => {
// 如果已经有待执行的了,就不需要再执行了,直接return;
if(timeoutKey){
return;
}
timeoutKey = setTimeout(() => {
// 别忘了把参数回传给fn
fn(...args);
// 函数执行完之后,记得把timeoutKey清空
timeoutKey = undefined;
}, interval)
}
}
手写Promise.all
// 覆盖原有构造函数中的静态方法
Promise.all = (promiseArr) => {
// 储存成功结果
let resolveList = [];
// 储存成功数量
let resolveNum = 0;
// promiseAll接受的promise数组长度
let promiseAllLength = promiseArr.length
// 返回一个新的promise,全部成功后调用resolve,有一个失败就直接调用reject
return new Promise((resolve, reject) => {
// 检查是否全部成功
function checkPromiseAllResolve(){
return resolveNum === promiseAllLength
}
// 遍历传进来的promiseArr
promiseArr.forEach((item, index) => {
// 下面这行主要是防止promiseArr中传递非Promise实例
// 用Promise.resolve方法可以 将非promise实例转化为promise实例,能理解就用
// Promise.resolve(item).then(res=>{
item.then(res=>{
// 成功返回储存在resolveList
resolveList[index] = res;
// 成功数量+1
resolveNum++
// 检查是否全部成功
if(checkPromiseAllResolve()){
// 如果全部成功了,把成功结果传出去
resolve(resolveList)
}
}).catch(err => {
// 任何一个失败了,都直接进行reject处理
reject(err);
})
})
})
}
模糊搜索
// 定义列表每一项的数据结构
type searchItem = {
value: string;
id: number;
}
// 模糊搜索的类型
type FuzzySearch = (list: searchItem[], searchVal: string) => searchItem[]
// 入参 searchItem[]和搜索的value,返回值也同样是数组
const fuzzySearch = (list, searchVal) => {
// 创建一个新的列表,储存筛选后的数据
const newList = [];
list.forEach( (item) => {
const { value, id } = item;
// 这里的搜索规则是只要包含就可以
// 具体规则由当时面试官定制,复杂一些的可能需要用到正则去匹配
if(
value.includes(searchVal) ||
id.includes(searchVal) ||
){
// 符合条件的储存在这里
newList.push(item);
}
});
// 把筛选后的数组返回出去
return newList
}
React TodoList
import React, { useState } from 'react';
import ReactDom from 'react-dom';
// 默认数据
const defaultData = {
title: '',
isDone: false,
time: +new Date()
}
const TodoList = function () {
// 储存代办列表
const [dataList, setDataList] = useState([]);
// 储存输入框输入信息
const [inputVal, setInputVal] = useState('');
// 向列表中添加
const addList = () => {
dataList.push({
...defaultData,
title: inputVal,
time: +new Date,
});
setDataList([...dataList]);
// 清空输入框
setInputVal('')
}
const onKeyDown = (e) => {
// 按下回车键
if(e.keyCode === 13){
addList();
}
}
const onChange = (e) => {
setInputVal(e.target.value);
}
const onClickItem = (item, index) => {
// 切换已完成或未完成状态
item.isDone = !item.isDone;
dataList[index] = item;
setDataList([...dataList])
}
const renderList = () => {
// 记录已完成列表
const doneList = [];
// 未完成列表
const todoList = [];
// 遍历数据源
dataList.forEach((item, index) => {
const { isDone, title, time } = item;
// 如果已完成push到已完成列表中
if(isDone){
doneList.push(<div key={time} onClick={() => onClickItem(item, index)}>{title}</div>)
return;
}
todoList.push(<div key={time} onClick={() => onClickItem(item, index)}>{title}</div>)
})
// 已完成列表和未完成列表分别渲染。
return (
<>
<div className="todoList">{todoList}</div>
<div className="doneList">{doneList}</div>
</>
)
}
return (
<div>
<div>
<input value={inputVal} onChange={onChange} onKeyDown={onKeyDown} />
<button onClick={addList}>添加</button>
</div>
<div>
{renderList()}
</div>
</div>
);
};
ReactDom.render(<TodoList />, document.getElementById('app'));
有趣的面试题 - 让 a == 1 && a == 2 && a == 3 成立
a为对象,重写valueOf方法实现
let a = {
value: 1,
valueOf: function() {
return this.value++;
}
};
console.log(a == 1 && a == 2 && a == 3); // 输出 true
a为数组,重写toString方法实现
let a = [1, 2, 3];
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3); // 输出 true
Proxy方法实现
let a = new Proxy({}, {
get: function(target, key) {
return key === 'valueOf' ? () => a.value++ : a[key];
}
});
a.value = 1;
console.log(a == 1 && a == 2 && a == 3); // 输出 true
使用 ES6 的 Symbol.toPrimitive 方法实现
let a = {
[Symbol.toPrimitive]: (function(i) {
return function() { return ++i; }
})(0)
};
console.log(a == 1 && a == 2 && a == 3); // 输出 true
Label Value 对齐
效果:
代码: