清除对象后会造成堆内存出现碎片的情况,当碎片超过一定限制后会启动压缩算法 。在压缩过程中,将活的对象向一端移动,直到所有对象都移动完成然后清理掉不需要的内存 。
其它考点0.1 + 0.2 !== 0.3因为 JS 采用 IEEE 754 双精度版本(64位),并且只要采用 IEEE 754 的语言都有该问题 。
不止 0.1 + 0.2 存在问题,0.7 + 0.1、0.2 + 0.4 同样也存在问题 。
存在问题的原因是浮点数用二进制表示的时候是无穷的,因为精度的问题,两个浮点数相加会造成截断丢失精度,因此再转换为十进制就出了问题 。
解决的办法可以通过以下代码:
export const addNum = (num1: number, num2: number) => {let sq1;let sq2;let m;try {sq1 = num1.toString().split('.')[1].length;} catch (e) {sq1 = 0;}try {sq2 = num2.toString().split('.')[1].length;} catch (e) {sq2 = 0;}m = Math.pow(10, Math.max(sq1, sq2));return (Math.round(num1 * m) + Math.round(num2 * m)) / m;};核心就是计算出两个浮点数最大的小数长度,比如说 0.1 + 0.22 的小数最大长度为 2,然后两数乘上 10 的 2次幂再相加得出数字 32,然后除以 10 的 2次幂即可得出正确答案 0.32 。
手写题防抖你是否在日常开发中遇到一个问题,在滚动事件中需要做个复杂计算或者实现一个按钮的防二次点击操作 。
这些需求都可以通过函数防抖动来实现 。尤其是第一个需求,如果在频繁的事件回调中做复杂计算,很有可能导致页面卡顿,不如将多次计算合并为一次计算,只在一个精确点做操作 。
PS:防抖和节流的作用都是防止函数多次调用 。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于阈值,防抖的情况下只会调用一次,而节流会每隔一定时间调用函数 。
我们先来看一个袖珍版的防抖理解一下防抖的实现:
// func是用户传入需要防抖的函数// wait是等待时间const debounce = (func, wait = 50) => {// 缓存一个定时器idlet timer = 0// 这里返回的函数是每次用户实际调用的防抖函数// 如果已经设定过定时器了就清空上一次的定时器// 开始一个新的定时器,延迟执行用户传入的方法return function(...args) {if (timer) clearTimeout(timer)timer = setTimeout(() => {func.apply(this, args)}, wait)}}// 不难看出如果用户调用该函数的间隔小于 wait 的情况下,上一次的时间还未到就被清除了,并不会执行函数这是一个简单版的防抖,但是有缺陷,这个防抖只能在最后调用 。一般的防抖会有immediate选项,表示是否立即调用 。这两者的区别,举个例子来说:
- 例如在搜索引擎搜索问题的时候,我们当然是希望用户输入完最后一个字才调用查询接口,这个时候适用延迟执行的防抖函数,它总是在一连串(间隔小于wait的)函数触发之后调用 。
- 例如用户给interviewMap点star的时候,我们希望用户点第一下的时候就去调用接口,并且成功之后改变star按钮的样子,用户就可以立马得到反馈是否star成功了,这个情况适用立即执行的防抖函数,它总是在第一次调用,并且下一次调用必须与前一次调用的时间间隔大于wait才会触发 。
// 这个是用来获取当前时间戳的function now() {return +new Date()}/** * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param{function} func回调函数 * @param{number}wait表示时间窗口的间隔 * @param{boolean}immediate设置为ture时,是否立即调用函数 * @return {function}返回客户调用函数 */function debounce (func, wait = 50, immediate = true) {let timer, context, args// 延迟执行函数const later = () => setTimeout(() => {// 延迟函数执行完毕,清空缓存的定时器序号timer = null// 延迟执行的情况下,函数会在延迟函数中执行// 使用到之前缓存的参数和上下文if (!immediate) {func.apply(context, args)context = args = null}}, wait)// 这里返回的函数是每次实际调用的函数return function(...params) {// 如果没有创建延迟执行函数(later),就创建一个if (!timer) {timer = later()// 如果是立即执行,调用函数// 否则缓存参数和调用上下文if (immediate) {func.apply(this, params)} else {context = thisargs = params}// 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个// 这样做延迟函数会重新计时} else {clearTimeout(timer)timer = later()}}}整体函数实现的不难,总结一下 。- 对于按钮防点击来说的实现:如果函数是立即执行的,就立即调用,如果函数是延迟执行的,就缓存上下文和参数,放到延迟函数中去执行 。一旦我开始一个定时器,只要我定时器还在,你每次点击我都重新计时 。一旦你点累了,定时器时间到,定时器重置为 null,就可以再次点击了 。
推荐阅读
- 不爱跳槽的程序员集中在8-17k,揭晓中国开发者的真实现状
- 大型Git仓库的部分克隆
- 数据仓库、数据集市、数据湖、数据中台这些概念,终于整明白了
- 银行数据仓库的系统架构是什么?看这篇足矣
- 数据仓库构建流程
- 长安|性价比超宏光MINI!长安奔奔E-Star国民版暂停收取订单:产能受限
- 数据仓库组件:Hive环境搭建和基础用法
- 10分钟自建企业级Docker镜像仓库!这个开源项目太顶了
- 一文带你搭建本地YUM仓库
- 开发框架搭建考量
