详解变量提升和闭包的应用

发布时间:2026/7/28 20:03:51

详解变量提升和闭包的应用 文章目录堆栈内存变量提升带var和不带var的区别作用域链的拓展闭包什么是闭包闭包的应用堆栈内存栈内存作用域提供一个供js代码自上而下执行的环境代码都是在栈内存中执行存储基本数据类型值释放当栈内存被销毁存储的那些基本值也跟着被销毁了一般函数执行完成所形成的私有作用域会自动释放除非某些内容被栈内存以外的变量占用了此时栈内存不能释放全局栈内存只有在页面关闭的时候被释放堆内存引用值对应的空间存储引用类型值对象键值对 函数代码字符串当前堆内存释放销毁那么这个引用值彻底没了释放当对内存没有被任何的变量或其他东西所占用浏览器会在空闲的时候自主进行内存回收把所有不被占用堆的内存销毁掉。比如我让ary1nullnull是空对象指针让原始变量谁都不指原有被占用的对内存就没有被东西占用了浏览器在空闲时候就把该堆内存销毁了。举例var a10经历三个过程声明变量a没有赋值默认是undefined在当前作用域开辟一个位置存储12栈让变量a和12关联在一起定义赋值var a[1,2]声明变量a开辟一个新的内存空间存储[1,2]堆让变量a和该对内存地址关联起来如果是函数的话会开辟一个新的内存空间存储代码字符串执行的时候开辟一个私有作用域栈把之前创建函数时存储的字符串执行执行完毕该栈内存销毁。变量提升js是先预编译再执行预编译的过程就是扫一遍把变量绑定作用域。所以才有变量提升。带var的只声明未定义带function的把声明定义都完成了console.log(a)console.log(sum)vara1functionsum(){console.log(hello world)}执行结果是【注意】私有作用域先形参赋值再变量提升再代码执行带var和不带var的区别在全局作用域下声明一个变量也相当于给window对象设置了一个属性属性的值就是属性值私有作用域声明的私有变量和window没关系console.log(a)//undefined 变量提升不报错conosle.log(window.a)//undefined 给window设置一个对象console.log(ainwindow)//true window存在a属性vara12console.log(a)//12conosle.log(window.a)//12如果不带var,看以下代码a12conosle.log(a)//12console.log(window.a)//12console.log(a)//报错 不执行a12conosle.log(a)console.log(window.a)console.log(window.a)//undefinedconsole.log(ainwindow)//falsea12//window.a 12conosle.log(a)//12console.log(window.a)//12【总结】在全局作用域加var是全局变量由于window对象和全局有映射关系也就设置了window的属性不加var的本质是window下的属性自然没有变量提升【拓展】在私有作用域中带var的在私有作用域有变量提升都声明为死于变量和外界没有任何关系不带var不是私有变量它会向它的上级作用域查找看是否为上级变量不是则继续向上查找一直查找到window位置这种查找机制叫做私有作用域链作用域链的拓展functionfn(){//变量提升无b13console.log(binwindow)//trueconsole.log(b)}fn();//13console.log(b)//13在作用域链查找过程中如果找到win也没有这个变量相当于给win设置了一个属性bwindow.b13闭包什么是闭包·存在没被释放的内存当前作用域使用其他作用域的变量比如functionb(){vara1returnfunctionc(){console.log(a)}}vareb()e()//输出1这就是个闭包b执行完了栈内存也没有被释放里面的a被b栈内存以外的变量引用。再看e执行的时候器作用域是全局作用域但使用到了b的私有作用域下的变量a闭包的应用为了保证js 的性能堆栈内存的性能优化应该尽可能减少闭包的使用不被销毁的堆栈内存是耗性能的闭包具有保护作用保护私有变量不受外界干扰在项目中尤其是团队写作开发的时候应尽可能减少全局变量的使用以防止相互之间的冲突那么此时哦我们可以把自己的一部分内容封装到一个闭包里让全局变量变为私有变量。基于return把需要供外面使用的方法暴露出去。varZepto(function(){//...return{xxx:function(){}}})或者当想改变一个对象的值比如user之前用user.name但这个方法不够好当程序过于复杂会一不小心改动一些东西变化的轨迹就非常难以追踪。虽然有效但非常危险。所以想把修改过程管控起来就用到了闭包。可以定义一个function user(name)。在里面var一个age,sex。这时候返回的不是一个确切的数值是一个对象对象里包含不同的方法比如getName,setName。方法就是定义在对象里面的函数。当做的项目内部数据流足够复杂那我们此处必须得找个办法来归纳不能让对象里面的值在里面被随便修改必须得找一个像一个接口一样的东西必须得按我的方法才能修改和设置某个值这样严谨很多。闭包可以通过走子函数来获取母函数的函数作用域然后去存取里面的值。这就是闭包的好处和特点。3. 闭包具有保存作用形成不销毁的栈内存把一些值保存下来方便后面的调取使用可以基于闭包解决用var for循环给多个按钮绑定事件无论点击第几个i都是最后那个。这个问题可以直接直接用let解决此处说用闭包解决的办法假如有五个按钮for(vari0;ibuttonList.length;i){buttonList[i].onclickfunction(){console.log(i)}}//此时无论点击第几个按钮打印的都是4因为js在es6之前没有块级作用域。当我们点击的时候外层循环已经结束可以点击的时候页面已经加载完成页面加载完成预示着js代码都已经执行完成也就是循环也都执行完成外层循环结束已经让全局下的i为4用闭包解决如下for(vari0;ibuttonList.length;i){buttonList[i].onclick(function(){//让自执行函数执行把执行的返回值(return)赋值给onclick此时onclick绑定的是返回的小函数点击的时候执行的是小函数自执行函数在给事件赋值的时候已经执行了returnfunction(){console.log(i)//上级作用域自执行函数形成的作用域}})()}

相关新闻