登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
3月21日 深圳|OpenClaw 线下实战沙龙:招聘、资讯、项目协同三大场景实操,VS ZeroClaw 横向对比评测,别再只会装,来现场跑通真实业务!
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
47
Fork
21
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
说说你对闭包的理解,以及闭包使用场景
待办的
#IAG9PM
陌生人
拥有者
创建于
2024-07-29 16:07
<h2>一、是什么</h2> <p>一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)</p> <p>也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域</p> <p>在 <code>JavaScript</code>中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁</p> <p>下面给出一个简单的例子</p> <pre><code class="language-js">function init() { var name = "Mozilla"; // name 是一个被 init 创建的局部变量 function displayName() { // displayName() 是内部函数,一个闭包 alert(name); // 使用了父函数中声明的变量 } displayName(); } init();</code></pre> <p><code>displayName()</code> 没有自己的局部变量。然而,由于闭包的特性,它可以访问到外部函数的变量</p> <h2>二、使用场景</h2> <p>任何闭包的使用场景都离不开这两点:</p> <ul> <li>创建私有变量</li> <li>延长变量的生命周期</li> </ul> <blockquote> <p>一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的</p> </blockquote> <p>下面举个例子:</p> <p>在页面上添加一些可以调整字号的按钮</p> <pre><code class="language-js">function makeSizer(size) { return function() { document.body.style.fontSize = size + 'px'; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16); document.getElementById('size-12').onclick = size12; document.getElementById('size-14').onclick = size14; document.getElementById('size-16').onclick = size16;</code></pre> <h3>柯里化函数</h3> <p>柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用</p> <pre><code class="language-js">// 假设我们有一个求长方形面积的函数 function getArea(width, height) { return width * height } // 如果我们碰到的长方形的宽老是10 const area1 = getArea(10, 20) const area2 = getArea(10, 30) const area3 = getArea(10, 40) // 我们可以使用闭包柯里化这个计算面积的函数 function getArea(width) { return height => { return width * height } } const getTenWidthArea = getArea(10) // 之后碰到宽度为10的长方形就可以这样计算面积 const area1 = getTenWidthArea(20) // 而且如果遇到宽度偶尔变化也可以轻松复用 const getTwentyWidthArea = getArea(20)</code></pre> <h3>使用闭包模拟私有方法</h3> <p>在<code>JavaScript</code>中,没有支持声明私有变量,但我们可以使用闭包来模拟私有方法</p> <p>下面举个例子:</p> <pre><code class="language-js">var Counter = function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } }; var Counter1 = Counter(); var Counter2 = Counter(); console.log(Counter1.value()); /* logs 0 */ Counter1.increment(); Counter1.increment(); console.log(Counter1.value()); /* logs 2 */ Counter1.decrement(); console.log(Counter1.value()); /* logs 1 */ console.log(Counter2.value()); /* logs 0 */</code></pre> <p>上述通过使用闭包来定义公共函数,并令其可以访问私有函数和变量,这种方式也叫模块方式</p> <p>两个计数器 <code>Counter1</code> 和 <code>Counter2</code> 是维护它们各自的独立性的,每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境,不会影响另一个闭包中的变量</p> <h3>其他</h3> <p>例如计数器、延迟调用、回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期</p> <h2>三、注意事项</h2> <p>如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响</p> <p>例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。</p> <p>原因在于每个对象的创建,方法都会被重新赋值</p> <pre><code class="language-js">function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; }; }</code></pre> <p>上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包。修改成如下:</p> <pre><code class="language-js">function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype.getName = function() { return this.name; }; MyObject.prototype.getMessage = function() { return this.message; };</code></pre>
<h2>一、是什么</h2> <p>一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)</p> <p>也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域</p> <p>在 <code>JavaScript</code>中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁</p> <p>下面给出一个简单的例子</p> <pre><code class="language-js">function init() { var name = "Mozilla"; // name 是一个被 init 创建的局部变量 function displayName() { // displayName() 是内部函数,一个闭包 alert(name); // 使用了父函数中声明的变量 } displayName(); } init();</code></pre> <p><code>displayName()</code> 没有自己的局部变量。然而,由于闭包的特性,它可以访问到外部函数的变量</p> <h2>二、使用场景</h2> <p>任何闭包的使用场景都离不开这两点:</p> <ul> <li>创建私有变量</li> <li>延长变量的生命周期</li> </ul> <blockquote> <p>一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的</p> </blockquote> <p>下面举个例子:</p> <p>在页面上添加一些可以调整字号的按钮</p> <pre><code class="language-js">function makeSizer(size) { return function() { document.body.style.fontSize = size + 'px'; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16); document.getElementById('size-12').onclick = size12; document.getElementById('size-14').onclick = size14; document.getElementById('size-16').onclick = size16;</code></pre> <h3>柯里化函数</h3> <p>柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用</p> <pre><code class="language-js">// 假设我们有一个求长方形面积的函数 function getArea(width, height) { return width * height } // 如果我们碰到的长方形的宽老是10 const area1 = getArea(10, 20) const area2 = getArea(10, 30) const area3 = getArea(10, 40) // 我们可以使用闭包柯里化这个计算面积的函数 function getArea(width) { return height => { return width * height } } const getTenWidthArea = getArea(10) // 之后碰到宽度为10的长方形就可以这样计算面积 const area1 = getTenWidthArea(20) // 而且如果遇到宽度偶尔变化也可以轻松复用 const getTwentyWidthArea = getArea(20)</code></pre> <h3>使用闭包模拟私有方法</h3> <p>在<code>JavaScript</code>中,没有支持声明私有变量,但我们可以使用闭包来模拟私有方法</p> <p>下面举个例子:</p> <pre><code class="language-js">var Counter = function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } }; var Counter1 = Counter(); var Counter2 = Counter(); console.log(Counter1.value()); /* logs 0 */ Counter1.increment(); Counter1.increment(); console.log(Counter1.value()); /* logs 2 */ Counter1.decrement(); console.log(Counter1.value()); /* logs 1 */ console.log(Counter2.value()); /* logs 0 */</code></pre> <p>上述通过使用闭包来定义公共函数,并令其可以访问私有函数和变量,这种方式也叫模块方式</p> <p>两个计数器 <code>Counter1</code> 和 <code>Counter2</code> 是维护它们各自的独立性的,每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境,不会影响另一个闭包中的变量</p> <h3>其他</h3> <p>例如计数器、延迟调用、回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期</p> <h2>三、注意事项</h2> <p>如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响</p> <p>例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。</p> <p>原因在于每个对象的创建,方法都会被重新赋值</p> <pre><code class="language-js">function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; }; }</code></pre> <p>上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包。修改成如下:</p> <pre><code class="language-js">function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype.getName = function() { return this.name; }; MyObject.prototype.getMessage = function() { return this.message; };</code></pre>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
Html/JS/CSS
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (
-
)
标签 (
-
)
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册