当前位置: 首页 > Web前端 > JavaScript

JavaScript闭包_0

时间:2023-03-26 20:47:50 JavaScript

本文将带你用正确的姿势看JavaScript闭包。在JavaScript中,闭包描述了函数外部作用域中的变量被内部作用域引用的场景。闭包的结构为内部作用域保存了外部作用域中的变量。要理解闭包,首先需要知道JS词法作用域是如何工作的。在JS词法作用域中查看这段代码:letname='John';functiongreeting(){letmessage='Hi';console.log(message+''+name);}变量名是全局变量。它可以在任何地方调用,包括在greeting函数内部。变量message是本地的,只能在greeting函数内部调用。如果尝试从greeting()外部访问message变量,会抛出错误:ReferenceError:messageisnotdefined更有趣的是函数内部的作用域可以嵌套,如下所示:functiongreeting(){let消息='嗨';函数sayHi(){console.log(消息);}sayHi();}greeting();//Higreeting()函数创建了一个局部变量message和一个局部函数sayHi()。sayHi()是greeting()的内部方法,只能在greeting()内部访问。sayHi()可以访问greeting()的消息变量。SayHi()在greeting()内部被调用,打印出变量message的值。JavaScript闭包(closures)来修改问候语:functiongreeting(){letmessage='Hi';函数sayHi(){console.log(消息);}returnsayHi;}lethi=greeting();hi();//还是可以获取到message的值。这次我们没有在greeting()中执行sayHi(),而是在调用greeting()时返回sayHi作为结果。在greeting()函数之外,声明了一个变量hi,它是sayHi()函数的索引。这时候我们通过这个索引执行sayHi()函数,可以得到和之前一样的结果。通常情况下,局部变量只在函数执行时存在,函数执行后会被垃圾回收机制回收。有意思的是,当我们在上面的方法中执行hi()时,message变量会一直存在。这就是闭包的作用,也就是说上面的形式就是一个闭包。其他示例以下示例说明闭包更有用的情况:functiongreeting(message){returnfunction(name){returnmessage+''+name;}}letsayHi=greeting('Hi');letsayHello=greeting('Hello');console.log(sayHi('John'));//你好Johnconsole.log(sayHello('John'));//HelloJohngreeting()接收一个参数(消息)并返回一个函数接收一个参数(名称)。greeting返回的匿名函数连接消息和名称。此时greeting()的行为类似于工厂模式。这用于创建sayHi()和sayHello()函数,它们都维护各自的消息“Hi”和“Hello”。sayHi()和sayHello()都是闭包。它们共享相同的函数体,但保持不同的作用域。防抖和节流面试的时候,面试官经常让你手写一个防抖和节流的函数,而真正用到的就是闭包。有兴趣的可以看看这篇文章《防抖和节流实例讲解》的好处和问题闭包的优点闭包可以将变量的状态保存在自己的作用域内,不会污染全局变量。因为如果很多开发者开发同一个项目,可能会造成全局变量的冲突。闭包可能导致的问题闭包的优势可能会成为一个严重的问题,因为闭包中的变量不能被GC回收,尤其是在循环中使用闭包时:functionouter(){constpotentiallyHugeArray=[];returnfunctioninner(){potentiallyHugeArray.push('Hello');//函数内部在potentiallyHugeArray变量上关闭console.log('Hello');};};constsayHello=outer();//包含函数innerfunctionrepeat(fn,num){for(leti=0;i