一、节流和防抖有什么区别?分别用于什么场景?
防抖
即防止抖动,抖动着就先不管它,等啥时候静止了再做操作。
例如,一个搜索输入框,等输入停止之后,自动执行搜索。

<template>
  <input type='text' @input='onInput' />
</template>

<script>
  import _ from 'lodash';

  export default{
  methods:{
    onInput: _.debounce(function(event){
      console.log('InputValue:',event.target.value)
    },1000)
  }
}
</script>

防抖实现

debounce(fn, delay = 200) {
  let timer = 0;

  return function () {
    if (timer) clearTimeout(timer);  // 如果定时器还没结束,则重置计时器重新计时

    timer = setTimeout(() => {
      fn.apply(this, arguments); //改变指向,向外部暴露内部变量
      timer = 0;
    }, delay);
  };
},

节流
即节省沟通交流。控制事件处理器被频繁触发的情况。
例如,drag的回调,上传进度的回调,都可以设置一个固定的频率,没必要那么频繁。

<template>
  <button @click="updateDataThrottle">点击</button>
</template>

<script>
  import _ from 'lodash'
  export default{
    methods:{
      updateData(){
        console.log('数据更新!')
      },
      updateDataThrottle: _.throttle(function(){
        this.updateData();
      },1000);   // 一秒钟内无论用户点击多少次按钮,都只会调用一次updateData()方法
    }
  }
</script>

节流实现

throttle(fn, delay = 200) {
  let timer = 0;

  return function () {
    if (timer) return; // 如果定时器还没结束,则返回空,等待上一次计时器结束执行完fn函数

    timer = setTimeout(() => {
      fn.apply(this, arguments); //改变this指向,向外部暴露内部变量
      timer = 0;
    }, delay);
  };
}

防抖和节流的共同点
都用于处理频繁触发的操作,优化操作体验。

防抖和节流的区别
触发频率:防抖不固定,节流固定
场景:防抖是结果式的,即一次调用即可;节流是过程式的,即需要持续一过程,一次不够。

二、px % em rem vw/vh的区别
px
像素,基本单位

%
相对于父元素的尺寸。
如根据 positon:absolute;居中显示时,需要设置left:50%

.container {
  width: 200px;
  height: 200px;
  position: relative;
}
.box {
  width: 100px;
  height: 100px;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -50px;
  margin-top: -50px;
}

em
相对于当前元素的font-size,首行缩进可以使用 text-indent: 2em。

rem
相对于根元素的font-size,可以根据媒体查询,设置根元素的 font-size,实现移动端适配。

@media only screen and (max-width: 374px) {
  html {
    font-size: 86px;
  }
}

@media only screen and (min-width: 375px) and (max-width: 413px) {
  html {
    font-size: 100px;
  }
}

@media only screen and (min-width: 414px) {
  html {
    font-size: 110px;
  }
}/

vw/vh
vw屏幕宽度的1%
vh屏幕高度的1%
vmin两者最小值
vmax两者最大值

三、手写深拷贝(避免循环引用的情况)

deepClone(value) {
  const cache = new Map();
  function _deepClone(value) {
    if (
      // 判断是否是基本数据类型或者null,如果是则直接返回
      Object.prototype.toString.call(value) !== "[object object]" &&
      value == null
    ) {
      return value;
    }
    if (cache.has(value)) {
      // 判断源对象是否已经存在map,如果是则直接取出源对象对应的克隆对象,避免循环引用造成递归错误
      return cache.get(value);
    }
    let newVal = Array.isArray(value) ? [] : {};
    cache.set(value, newVal);
    for (const key in value) {
      if (
        Object.prototype.toString.call(value[key]) !== "[object object]" &&
        value[key] == null
      ) {
        return (newVal[key] = value[key]);
      } else {
        return _deepClone(value[key]);
      }
    }
    return newVal;
  }
  return _deepClone(value);
},

四、箭头函数的缺点、什么时候不能使用箭头函数
缺点
1.箭头函数没有arguments、call、callee
2.箭头函数内部无法通过call、apply、bind等改变this指向
3.箭头函数没有原型属性
不适用箭头函数的场景
1.箭头函数不建议用作对象方法

const obj = {
  name: "abc",
  getName: () => {
    return this.name;  // 这里的this指向父作用域
  },
};
console.log(obj.getName()); //undefined;

2.对象原型、构造函数、动态上下文、Vue生命周期和方法
关键原因就在于会箭头函数会改变this指向,指向父作用域

五、TCP连接 三次握手 四次挥手
建立连接
客户端和服务端通过HTTP协议发送请求,并获取内容。
在发送请求之前,需要先建立连接,确定目标机器处于可接受请求的状态。
HTTP协议是一个应用层协议,它只规定了req和res的数据格式,如状态码、header、body等。
而建立网络连接需要更加底层的TCP协议。

三次握手
1.客户端发送一个包含SYN标志的TCP报文到服务器。 //客户端:测试一下服务端能不能收到
2.服务端收到请求后,发送一个包含SYN和ACK标志的TCP报文作为应答。 //服务端:能收到,我也给你发一个报文看你能不能收到
3.客户端再回应一个包含ACK标志的TCP报文,完成三次握手。 //客户端:收到了,开始建立连接吧

至此,建立连接完成,然后开始发送数据,通讯。

四次挥手
1.客户端发送一个包含FIN标志的TCP报文到服务器,表示数据发送完毕。 //客户端:我请求完了
2.服务端收到包含FIN标志的TCP报文后,发送一个包含ACK标志的TCP报文表示确认。 //服务端:知道了,等我响应完你的请求就关闭连接
3.服务器完成数据发送后,发送一个包含FIN标志的TCP报文。 //服务端:我响应完了,可以关闭连接了
4.客户端回应一个包含ACK标志的TCP报文,完成挥手。 //客户端:关闭了

六、for...in 和 for...of的区别
1.for...in是通过普通对象遍历可枚举属性来获取对象键名(key)

可枚举属性:指的是对象下属性的enumerable为true
例如:对象、数组、字符串

2.for...of是通过可迭代对象循环迭代来获取对象键值(value)

可迭代对象:数组、Map、Set、字符串等实现了`iterator()`和`next()`方法的对象

七、offsetHeight、scrollHeight、clientHeight的区别


rirmk
178 声望18 粉丝

目标资深web前端工程师!!


« 上一篇
TS基础