前端八股整理|JavaScript|高频小题 03
文章目录前端八股整理JavaScript高频小题 031.闭包2.防抖和节流3. Map 和 foreach 的区别,map 会不会改变原数组前端八股整理JavaScript高频小题 031.闭包在理解闭包之前,可以了解一下词法作用域和作用域链词法作用域:一个函数的作用域链它能访问哪些变量在它被‘定义’或‘创建’的那一刻就已经确定了并且永远不会改变。它与函数在“哪里被调用”完全无关。作用域链可以理解为当代码访问一个变量时会先在当前作用域查找如果找不到就沿着外层作用域一层层向上查找直到全局作用域。来看一个例子,深入理解作用域链和词法作用域functionbar(){console.log(a);}functionfoo(){vara100bar()}vara200foo()bar 中调用的 a 的上一层是全局定义域中的 a200,这是定义就被规定好的所以在 foo 中调用的时候 打印的是 200 不是 100闭包?闭包可以理解为一个函数记住它被创建时的词法环境,即使是在这个函数作用域之外执行,也能够正常访问.简单来说,闭包内层函数引用的外层函数变量动手实现一个闭包:consta1;functionfn(){console.log(a)}此时通常会在使用一个函数包裹住闭包结构,起到对变量保护的作用functionouter(){consta1;functionfn(){console.log(a)}fn();}outer();此时就已经形成了闭包,调用 outer,在开发工具中国已经形成了闭包环境/闭包结构(内部函数 fn 引用了外部函数 outer 的变量a)这也说明了 闭包不是一定需要 return 的,只是在实际使用的过程中为了让外部能够访问到数值,需要 return 出来functionouter(){consta1;functionfn(){console.log(a)}returnfn;}constfunouter()此时多次使用 fun 同样打印出 1,2,3,4,但是如果要修改 a1000 是不行呢,闭包的租用就是实现数据的私有内存泄漏?可以看到 count 会内存泄露,因为 fun 是一个全局变量,代码执行完毕后不会立即销毁,fun 使用 outer 函数,outer函数又使用着 fn 函数,fn 函数里用到了 count,count 一直被引用,所以一直存在注意:不是所有的内存泄漏都要手动回收,react 中很多闭包不能回收2.防抖和节流什么是防抖?单位时间内,频繁触发事件,每次触发都从头开始重新开始计时只有在停止触发一段时间后函数才真正执行一次。典型场景:搜索框搜索输入,输入的时候就是频繁触发事件的过程,只有输入完之后多长时间之后,才发送请求.代码思路:利用定时器,每次触发先清掉以前的定时器(从新开始)手写防抖:bodydiv idappinput typetextidinputplaceholder请输入内容/divscript//防抖constinputdocument.getElementById(input);functiondebounce(fn,delay){lettimernullreturnfunction(...args){clearTimeout(timer)timersetTimeout((){fn.apply(this,args);},delay)}}functionsendRequest(){console.log(已发送请求)}constdebounceSenddebounce(sendRequest,1000);input.addEventListener(input,debounceSend);/script/body函数讲解:参数传递:debounce(sendRequest,1000)首先会把这两个参数传给 debounce 函数,debounce 函数返回一个新的函数此时 debounceSend 就是这个新的函数,此时像 debounceSend 传的参数就是那个 args 收集的参数input 的监听事件,就会默认传入一个 event 事件,所以 args 就是这个 event 事件普通函数作为 dom 函数的回调函数来说,this 指向的就是这个 dom 元素,因为箭头函数没有自己的 this,所以 debounce 中的 this 就是 dom 元素,apply 就是强制让这个的 this指向,同时传了参数,然后调用为什么需要闭包?因为用复用这个 timer,因为需要在多次触发之间,记住上一次的定时器是谁,如果记不住上一次的 timer 就没法清空正确的 timer,重新开始计时,timer不放在全局,而是放在闭包中,核心是怕污染全局,每个防抖函数有独立的 timer,外部不可以随便修改它什么是节流?单位时间内,频繁触发时间,但是只执行一次典型场景:快速点击,鼠标滑动,resize 事件,scroll 事件代码思路也是利用定时器,等定时器执行完毕,才开启定时器(不打断)手写节流:bodydiv idappbutton idbtn点击发送请求/button/divscript//节流constbuttondocument.getElementById(btn);functionthrottle(fn,delay){letcanruntrue;returnfunction(...args){if(!canrun)return;canrunfalse;fn.apply(this,args);setTimeout((){canruntrue;},delay)}}functionsendRequest(){console.log(已发送请求)}constthrottleSendthrottle(sendRequest,5000);button.addEventListener(click,throttleSend);/script/body实际开发过程中,可以使用 lodash库,利用里面的 debounce(防抖)和 throttle(节流)来做3. Map 和 foreach 的区别,map 会不会改变原数组map会遍历数组会把每一项处理后的结果组成一个新数组返回不直接修改原数组前提是你回调里没手动去改原数组元素forEach也会遍历数组没有返回新数组返回值是 undefined通常用来做“执行动作”比如打印、赋值、发请求这里的 map 和 forEach 一般指的是数组方法。两者都会遍历数组但区别在于 map 会根据回调函数的返回值生成一个新的数组而 forEach 只是遍历执行不会返回新数组它的返回值是 undefined。正常使用下map 不会修改原数组除非在回调内部手动去改原数组元素forEach 也不会自动返回新数组更多是用来做打印、赋值、请求这类副作用操作。