1、什么是防抖,什么是节流?
防抖
在事件被触发时,延迟n秒后再触发回调函数,如果n秒内又触发了事件,则会重新开始计算时间(一定时间内最后一次生效)
-
应用场景
- 用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源
-
实现
-
function debounce(fn,delay){ let timer = null; return function(){ if(timer){ clearTimeout(timer) } timer = setTimeout(fn,delay) } }
-
节流
一段时间内只能触发一次,如果这段时间内触发多次事件,只有第一次生效会触发回调函数,一段时间过后才能再次触发(一定时间内只执行第一次)
-
应用场景
- 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次
- 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源
-
实现
-
function throttle(fn,delay){ let flag = true; return function(){ if(flag){ flag = false; setTimeout(() =>{ flag = true },delay) return fn() } } }
-
2、如何实现闭包?
闭包
由作⽤域嵌套产⽣的执⾏空间不被销毁的场景(⼤函数嵌套⼩函数,⼩函数使⽤⼤函数的变量,⼤函数外跟⼩函数保持联系)函数内部的变量可以访问函数外部的变量,函数外部的不可以访问函数内部的变量。
-
实现
-
function test() { var a = 1 function cc() { console.log(a++); } return small } var s = test() s() // 1 s() // 2 s() // 3
-
-
使用场景
- 在循环中绑定事件,事件函数中需要使⽤循环的变量
- 在循环中执⾏异步代码,在异步代码中使⽤循环的变量
- 防抖
- 节流
- 函数柯⾥化
3、介绍函数调用时的执行步骤?
函数的两大阶段:定义阶段和调用阶段
- 定义阶段:
- 在内存开辟空间
- 把函数体中的代码,存放在该空间中
- 把该空间的引用地址,返回给函数
- 调用阶段:
- 根据函数名中的引用地址,获取内存中的函数体
- 给形参赋值
- 预解析
- 在内存中再次开辟一个执行空间
- 把存储空间中的代码,拿到执行空间中去执行
- 当执行空间中的代码执行完毕时,销毁执行空间
4、let、const和var关键字的区别?
(1)块级作用域: 块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了
ES5中的两个问题:
- 内层变量可能覆盖外层变量
- 用来计数的循环变量泄露为全局变量
(2)变量提升: var存在变量提升,let和const不存在变量提升,即变量只能在声明之后使用,否在会报错。
(3)给全局添加属性: 浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量, 并且会将该变量添加为全局对象的属性,但是let和const不会。
(4)重复声明: var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const和let不允 许重复声明变量。
(5)暂时性死区: 在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。 使用var声明的变量不存在暂时性死区。
(6)初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
(7)指针指向: let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新 赋值)。但const声明的变量是不允许改变指针的指向。
5、箭头函数和普通函数的区别?
- 箭头函数比普通函数更加简洁
- 箭头函数没有自己的this
- 箭头函数继承来的this指向永远不会改变
- call()、apply()、bind()等方法不能改变箭头函数中this的指向
- 箭头函数不能作为构造函数使用
- 箭头函数没有自己的arguments
- 箭头函数没有prototype