本文默认处于折叠状态,可点击标题后方的 … 展开或闭合。
参考链接:
JavaScript
节流和防抖
防抖:动作发生后,延时多久后执行动作回调
比如:点击事件,点击之后在一定时间后触发回调,在该时间内如果再发生点击事件 不会立即触发回调,而是重置延时触发时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
function debounce(fn, time) { let timer = null return function() { clearTimeout(timer) timer = setTimeout(() => fn.apply(this, arguments), time) } } function log(time) { setTimeout(() => console.log('x: ' + time), time || 10) } const dlog = debounce(log, 100) dlog(10) dlog(50) dlog(100) dlog(120)
x: 120
10, 50, 100 都没触发,因为执行间隔都不超过 100 所以被
clearTimeout
取消了, 知道第四个dlog(120)
调用,后面没有了,得到执行输出结果。节流:两个动作触发有一定的时间间隔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
function throttle(fn, duration) { let last = 0 return function() { let current = Date.now() if (current - last < duration) return fn.apply(this, arguments) last = Date.now() } } function log(time) { console.log('x: ' + time) } function delay(time) { setTimeout(() => dlog(time), time) } // 100ms 间隔 const dlog = throttle(log, 100) delay(10) delay(50) delay(150) delay(160) delay(270)
x: 10 // now - 0 >= 100 x: 150 // 150 - 50 >= 100 x: 270 // 270 - 160 >= 100
防抖和节流区别
防抖 是指同一种类型的动作无论发生多少次,只要间隔时间不够长,就永远只会触发
最后那一个动作回调
。节流 是指两个动作中间必须间隔特定的时间,否则后面的动作不会触发,即在这固 定的时间间隔之内的动作会被忽略,
只会执行第一个动作回调
。
测试:
下面的代码打印什么?
IIFE 函数名是个常量?
函数定义实现原理: http://ecma-international.org/ecma-262/5.1/#sec-13
非严格模式
1 2 3 4 5 6
var b = 10 ;(function b() { b = 20 console.log(b) })()
[Function: b]
输出结果分析:非严格模式下 IIFE 的函数名不能进行赋值,如果赋值了的话静默是失 败的,所以说
b = 20
这一句没其任何作用,函数内部的b
还是 IIFE 的那个函数 名,所以最后输出依旧是[Function: b]
。严格模式
1 2 3 4 5 6 7 8 9 10 11
var b = 10 try { ;(function b() { "use strict"; b = 20 console.log(b) })() } catch(e) { console.log(e) }
TypeError Assignment to constant variable.
结果分析:将 IIFE 内部换成严格模式就能很明显的说明问题了,上面结果报错“不能给 常量赋值”,立即函数名是不可变的常量。
window.b/this.b
1 2 3 4 5 6 7 8
var b = 10; (function b() { b = 20 console.log(b) console.log(this.b) // 10 })()
[Function: b] 10
因为这里是以 node module 环境运行的,所以不能直接使用
window.b/this.b/global.b
去取到外面的var b = 10
的值,结果是根据浏览器环境 运行结果。第二个 log 结果是 10 ,原因是在全局作用域下用
var
声明的变量是全局变 量,会挂到 window 对象下面,所以可以直接通过 window.b 取到它的值,用 this.b 也能取到是因为 IIFE 函数调用上下文是在全局,所以 this 指向 window 。函数提升(声明+赋值)
1 2 3 4 5 6 7 8 9 10 11 12 13
var b = 10 function b() { b = 20 console.log(b) } console.log({ b }) try { b() } catch(e) { console.log(e.message) }
{ b: 10 } b is not a function
结果分析:提升对于命名式函数表达式来说,它的声明和赋值都会被提升,对于
var
声明的变量只会提升声明,所以就有function b
声明和赋值提升,var b
声明提升,由于声明只会发生一次, 所以这里相当于只有一次声明和赋值,即此时有变量b
它的值是function b() {}
。但是
var b = 10
的赋值不会提升,所以当执行到这一句的时候,b
的值 会被这里的赋值操作给替换成10
。
只有
b = 10
1 2 3 4 5 6 7 8
function b() { console.log(b) // [Function b] b = 1 console.log(window.b) // 1 console.log(b) // 1 } b()
[Function b] 1 1