JS笔记-fn.apply、this、防抖函数
JS笔记-fn.apply、this、防抖函数
到底为什么写func.apply(this, arguments)掘金
防抖函数是指,在一定时间间隔内,如果没有重复触发函数,才会执行函数体的代码(防止在很短的时间里多次触发的函数),例如网络请求,input输入,浏览器resize监听等。
以下是防抖函数的一个基本实现,通过闭包将主函数体放在timer计时器里,如果二次调用了func,就会通过clearTimeout取消计时器的后续操作,达到防止函数重复触发的效果。
1 | function debounce(func, delay) { |
其中这个func.apply(this, arguments);
看上去是触发函数的作用,但this
和arguments
两个参数是什么作用呢?
在js里,this指向当前作用域,只有在运行时才会明确其指向的对象。通过apply的使用,可以修改当前函数的作用域对象:
1 | var name = 'a', age = 0, type = 'A' |
如上述代码所示,fn通过apply成功修改了this指向,输出了obj的内容。
插个题外话,以上代码只能在浏览器中运行,如果放在node环境里直接调用fn()
只会输出三个undefined
。那这个this到底指向哪里了呢?
在浏览器或 Node.js 的全局作用域中,this
都默认指向全局对象。浏览器中的对象是 window
,而Node.js 中是 global
。与let
和const
不同,var
声明的变量会成为 window
的属性,因此 this.name
可以访问到值。在浏览器里通过var声明的全局变量是可以通过window
直接拿到的:
1 | var name1 = "name1"; |
但在node环境里,var
变量属于模块作用域,不会挂载到 global
对象,因此全局环境下 this.name1
始终为 undefined
:
1 | var name1 = "name1"; |
明白了this的作用,就很明确func.apply(this, arguments)
的使用了。
除了apply()方法外,call()方法也与其类似,但在传参上略有不同。call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
还有一个bind()方法,不同的是此方法会创建一个新的函数,需要重新调用。(bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。)
1 | var name = 'a', age = 0, type = 'A' |
理解了以上知识后,我们再回到防抖函数,观察一下是怎么调用的:
1 | const obj = { |
我们在调用时传入了一个作用域,这个作用域是如何传入fn函数里的呢?原理就在这句回调函数里:
1 | timer = setTimeout(()=>{ |
setTimeout里的回调函数会自动继承父级的作用域,也就是testDebounce的作用域。我们通过call()修改了作用域,也就成功实现了作用域传递。