一、节流和防抖有什么区别?分别用于什么场景?
防抖
即防止抖动,抖动着就先不管它,等啥时候静止了再做操作。
例如,一个搜索输入框,等输入停止之后,自动执行搜索。
<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的区别
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。