作用域
作用域:运行代码时,变量/函数/对象的可访问性
好处:有独立的空间,变量不会暴露,即允许不同作用域下同名变量
全局作用域:任何地方都能访问到(容易命名冲突)
局部作用域:在固定代码段可访问(引发变量提升、预解析)
es6块级作用域:使用let/const关键字定义在代码块中(不会变量提升)
变量提升:先声明再调用,同名变量函数优先
作用域链
在函数内部调用某个变量,若当前作用域没有,则会一层层往上找,这就形成了作用域链。若最外层也没有,则会显示xx is not defined
undefined:定义了,但未赋值
is not defined:没有定义,报错
null:空对象
闭包——函数内外部的桥梁
函数嵌套函数,内部函数(调用了外部函数的变量)就叫闭包
使用场景:防抖节流、设计单例模式
正常情况下,函数执行完后,需要释放内存空间,那么内部变量会被销毁
存在意义:1、能读取外函数的内部变量 2、缓存变量,不会被销毁(内外函数变量,相互依赖)
注意事项:1、不随意改变父函数中变量 2、不滥用闭包,变量保存在内存中,内存消耗大,容易造成内存泄漏
内存泄漏
不再使用的变量,由于某些原因,没有被释放 => 内存消耗大
结果:造成内存泄漏,浪费系统内存,程序运行速度减慢,甚至崩溃
解决措施:少用闭包、少用全局变量、定时器写完要释放、少用事件监听器
故许多语言(c#/js/java)都自带内存管理机制,也就是俗话说的垃圾回收机制
回收对象:不再使用的变量,释放他们占用的内存,且会按固定时间回收
防抖
用户触发事件过于频繁,只让最后一次输入生效
使用场景:搜索框输入时、窗口大小resize、手机号/邮箱验证输入检测
//获取一次完整的输入值
function debounce(fn,delay){
let timer=null
return function(){
if(timer!==null){
clearTimeout(timer)
}
timer=setTimeout(()=>{
// console.log(this)
// call:1、改变this指向 2、调用函数
fn.call(this)
},delay)
}
}
let v=document.querySelector('input')
v.oninput=debounce(function(){
console.log(this.value)
},500)
节流
控制高频事件执行的次数
使用场景:滚动加载、搜索框搜索功能
//一定时间内执行一次(懒加载)
function throttle(fn,delay){
let flag=true
return function(){
if(flag){
setTimeout(()=>{
fn()
flag=true
},delay)
}
flag=false
}
}
window.onscroll=throttle(()=>{
console.log('我在滚动')
},500)