前端面经--我一定要跳槽成功


–记录到进大厂为止

CSS

position

  • static: 默认。就是自然顺序,从上到下,从左到右,爱着你排列;
  • absolute:绝对。原点是:最近的非static的父(上级)元素。
    • dom是一棵树。当前节点的父节点如果是absolute或relative,那么原点就是父节点,如果不是,那么就找父亲的父亲,而不是找父亲的兄弟,或自己的兄弟。
  • fixed: 固定。相对于浏览器。
  • relative:相对。相对于正常文档流中的自己。
  • inherit:继承父元素

JS

手写防抖和节流

防抖

基本函数
// 初级防抖函数
function debounce(fn,delay){
    let timer;
    return function(...args){
        clearTimeout(timer);
        timer=setTimeout(()=>fn.apply(this,args),delay);
    }
}

// 自定义
let d=debounce(()=>console.log("excute fu"),100);

// 抖动5次,只会执行最后一次
for(let i=0;i<5;i++){
    d();
}
// 输出
// excute fu
防抖是什么?防止抖动。如果一直抖动,只执行最后一次。
闭包的应用
  • 什么是闭包?函数+函数访问的变量。特点是可以访问函数外面的变量;其实debounce本质上返回的是一个函数定义,也就是下面的d函数,显然,d函数访问了d函数外的timer,那么d函数和timer构成了闭包。这也是实现防抖的关键。
  • timer变量,只要有函数引用,就不会消失。五次抖动中(循环),每次循环,都返回了debounce的d函数,我们可以对应成d1,d2,d3,d4,d5;实际上di都访问了timer,然后,di+1会清除掉di创建的timer,并且将timer指向新的timer,其实也就是覆盖。由此,只有最后一次会生效。
function debounce(fn,delay){
    let timer;
    let d=function(...args){
        clearTimeout(timer);
        timer=setTimeout(()=>fn.apply(this,args),delay);
    }
    return d;
}
进阶函数
  • 怎么实现立刻执行?上面的实现效果是,n次抖动中,只执行第n次,并且,是在第n次发生delay时间后执行fn函数。那么,如果希望n次抖动中,执行且仅执行第1次呢?也就是所谓的立马执行。
// 进阶
function debounce(fn,delay,immedate){
    let timer;
    let d=function(...args){
        clearTimeout(timer);
        if(immedate){
            let callNow=!timer;  // callNow只有第一次会为真
            timer=setTimeout(()=>timer=null,delay);// delay有没有都无所谓,不影响,这里只是说最后一次抖动完之后,delay时间后,再彻底清除掉timer。
            if(callNow){
                fn.apply(this,args);
            }
        }else{
            timer=setTimeout(()=>fn.apply(this,args),delay);
        }
    }
    return d;
}




let d=debounce(()=>console.log("excute fu"),100,true);


for(let i=0;i<5;i++){
    d();
}
  • callNow控制第一次执行。上述逻辑,只有d1的时候,callNow是真,因为timer初始状态为null;d2,d3,d4,d5的时候timer都不会为null;因为timer=setTimeout(()=>timer=null,delay);// delay有没有都无所谓,不影响,这里只是说最后一次抖动完之后,delay时间后,再彻底清除掉timer。
    等到最后一次,也就是d5执行了,隔delay后,清除timer;

节流基本函数

节流定义

节流就是在一定时间内只执行一次。

防抖:执行最后一次 vs 节流:每隔一定时间内执行且只执行一次

// 基础
function throttle(fn,await){
    let timer;
    return function (...args) {
        if(!timer){
            timer=setTimeout(()=>{
                fn.apply(this,args);
                timer=null; // 不能用clearTimeout清除定时器;因为只是暂停了,打印timer还是会有值,那么if(!timer)等于没用了
            },await); 
        }     
    }
}
  • 有timer就略过,没有timer就指定新的定时器;唯一需要注意的可能就是timer=null,而不是clearTimeout(timer);当然,为了防止内存泄露,也是可以上句话的。
进阶函数
  • 节流一般问的可能就是,定时器不一定准确,那么你怎么控制?
  • 首先,定时器为什么不准确。
    • 浏览器本身因素,设备熄屏计时器可能会暂停啊什么的
    • 事件循环机制
      • setTimeout属于宏任务。计时器结束之后的函数会进入宏任务队列。宏任务队列之前可能有其他函数。

由此可见,首先是你定时器本来就不准,其次是就算准确了,进入队列,也有可能需要等其他任务执行完了,才能执行定时器的回调函数。那么,我们至少可以控制第一个因素,定时器本身就不准确——时间戳解决。

function throttle2(fn,awaitt) {
    let timer;
    let start=Date.now();
    return function (...args) {
        let now=Date.now();
        let remain=awaitt-(now-start);
        clearTimeout(timer); // 如果有程序一直调的话,需要清除上一次产生的定时器
        if(remain<=0){ // 到时间了,直接执行;
            fn.apply(this,args);
            start=Date.now(); // 重置;
        }
        else{ // 如果函数只被触发了一次
            timer=setTimeout(fn,remain); // 还剩remian时间到达指定的awaitt时间长度;
        }
    }
}
  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值