手写js各种函数
防抖节流(多个面试)
防抖
单位时间内频繁的触发事件,只执行最后一次
下面是最简单的写法
function debounce(fn, t){
let timeid;
return function(args){
if(timeid){
clearTimeout(timeid)
}
timeid = setTimeout(()=>{
fn()
}, t)
}
}
如何获取fn的参数
function debounce(fn, t){
let timeid;
return function(args){
let argu = arguments; //获取参数
if(timeid){
clearTimeout(timeid)
}
timeid = setTimeout(()=>{
fn.apply(this, argu)
}, t)
}
}
debounce(fun, 100)(argu1, argu2);
节流
单位时间内频繁的触发事件,只执行第一次
function throttle(fn, t){
let timeid;
return function(args){
let argu = arguments; //获取参数
if(timeid){
}else{
timeid = setTimeout(()=>{
fn.apply(this, argu)
timeid = null //清空计时器
}, t)
}
}
}
debounce(fun, 100)(argu1, argu2);
数组拍平
递归调用
function fn(arr){
let res = []
arr.forEach((val) => {
if(val instanceof Array){
res = res.concat(fn(val))
}else{
res.push(val)
}
})
return res;
}
reduce和递归
function fn(arr){
return arr.reduce((prev, cur)=>{
return prev.concat(Array.isArray(cur)? fn(cur):cur)
}, [])
}
reduce方法
arr.reduce((prev,cur,index,arr)=>{
},init)
- arr: 表示原数组
- prev:表示上一次调用回调时的返回值,或者初始值init
- cur:表示当前正在处理的数组元素
- index:表示正在处理的数组元素的索引,若提供init值,则索引为0,否则索引为1,此时prev为第0个元素,cur为第一个元素
- init: 表示初始值
flat
ES6新增的嵌套数组转一维数组的方法flat
flat(n)
如果不传递参数n的话,flat函数默认只展开一层;n的值为多少就展开多少层;如果想无论多少层都展开为一维数组,则将参数值设为Infinity。flat函数在拍平过程中还会自动跳过数组中的空位。
arr.flat(Infinity)
算法题
动态规划
斐波那契数列(途虎养车、去哪儿一面)
使用动态优化写出斐波那契数列后,还要考虑空间复杂度的优化
回溯
二叉树中和为目标值的路径(百度一面)
题目
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
代码
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} target
* @return {number[][]}
*/
var pathTarget = function(root, target) {
// 存储结果的数组
const res = [];
// 回溯用的栈
const stack = [];
// 开始回溯
root && backTrack(root, target, stack, 0, res);
return res;
};
const backTrack = (node, targetSum, stack, sum, res) => {
// 将节点入栈
stack.push(node.val);
// 节点加入到sum中
sum += node.val;
// 到达了叶子节点,并且当前记录的sum正好满足条件
if (!node.left && !node.right && sum === targetSum) {
// 将栈中的节点拷贝一份,推入返回结构res中
// 若不拷贝的话,推入的是引用,stack改变,res里的stack也会改变
res.push([...stack]);
}
// 如果存在左节点,继续遍历左子树,右子树同理
node.left && backTrack(node.left, targetSum, stack, sum, res);
node.right && backTrack(node.right, targetSum, stack, sum, res);
// 向上回溯,stack弹出一个节点
// 这里sum没有回溯是因为backTrack调用时将每一次的sum传入了函数中,递归函数返回后还是原本的值
stack.pop();
};
链表
翻转链表(百度一面)
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
var reverseList = function(head) {
let p1 = head, p2 = null
let temp = null
while(p1){
temp = p1.next
p1.next = p2
p2 = p1
p1 = temp
}
return p2
}
场景题
React里面实现count每一秒加一
function Counter(){
const [count, setCount] = useState(0)
useEffect(()=>{
const timeId = setInterval(()=>{
setCount(t => t+1) //setCount函数可以传入一个函数,来控制如何更改count,这样不会依赖count
}, 1000);
return ()=> clearInterval(timeId);
}, [])
return <div>{count}</div>;
}