Loading... <h2>什么是闭包?</h2><p>红宝书(p178)上对于闭包的定义:闭包是指有权访问另外一个函数作用域中的变量的函数,</p><p>MDN 对闭包的定义为:闭包是指那些能够访问自由变量的函数。</p><p>由此,我们可以看出闭包共有两部分组成:</p><ul><li>是一个函数</li><li>能访问另外一个函数作用域中的变量</li></ul><p>对于闭包有下面三个特性:</p><p>1、闭包可以访问当前函数以外的变量</p><pre><code>function getOuter(){ var date = '815'; function getDate(str){ console.log(str + date); //访问外部的date } return getDate('今天是:'); //"今天是:815" } getOuter(); </code></pre><p>2、即使外部函数已经返回,闭包仍能访问外部函数定义的变量</p><pre><code>function getOuter(){ var date = '815'; function getDate(str){ console.log(str + date); //访问外部的date } return getDate; //外部函数返回 } var today = getOuter(); today('今天是:'); //"今天是:815" today('明天不是:'); //"明天不是:815" </code></pre><p>3、闭包可以更新外部变量的值</p><pre><code>function updateCount(){ var count = 0; function getCount(val){ count = val; console.log(count); } return getCount; //外部函数返回 } var count = updateCount(); count(815); //815 </code></pre><p>为什么闭包的应用都有关键词 return,引用 JavaScript 秘密花园中的一段话:</p><p>闭包是 JavaScript 一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。 因为 函数 是 JavaScript 中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。</p><h2>应用场景</h2><p>具体应用场景你知道哪些??</p><ul><li>保护函数内的变量安全:如迭代器、生成器。</li><li>在内存中维持变量:如缓存数据、柯里化。</li></ul><p>私有属性</p><pre><code>var foo = (function(){ var secret = 'secret' // “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的 return { get_secret() { return secret }, new_secret(new_secret) { secret = new_secret } } })() foo.secret // undefined foo.get_secret() // 'secret' foo.new_secret('哈哈哈') // 修改secret值 foo.get_secret() // '哈哈哈' </code></pre><p>之所以可能通过这种方式在 JavaScript 种实现公有,私有,特权变量正是因为闭包,闭包是指在 JavaScript 中,内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。</p><pre><code>let sque = (function () { let _width = Symbol(); class Squery { constructor(s) { this[_width] = s } foo() { console.log(this[_width]) } } return Squery })(); let ss = new sque(20); ss.foo() // 20 console.log(ss[_width]) // ReferenceError: _width is not defined </code></pre><p>单例模式</p><pre><code>class Modal { constructor(name) { this.name = name this.getName() } getName() { return this.name } } let ProxySing = (function(){ let instance; return function(name) { if (!instance) { instance = new Modal(name) } return instance } })() let a = new ProxySing('问题框'); let b = new ProxySing('回答框'); console.log(a === b); // true console.log(a.getName()); // '问题框' console.log(b.getName()); // '问题框' </code></pre><p>函数防抖</p><pre><code>const fn = () => console.log('fn') window.onresize = debounce(fn, 1000) function debounce(fn, interval) { let timer = null; return function (...args) { if(timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, interval); } } </code></pre><h2>面试题</h2><p>接下来,看这道刷题必刷,面试必考的加强版闭包题:</p><pre><code>for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 1000); } console.log(i) // 5 5 5 5 5 5 </code></pre><p>答案是都是5,6个5,让我们分析一下原因:</p><p>由于作用域链机制的影响,闭包只能取得内部函数的最后一个值,这引起的一个副作用就是如果内部函数在一个循环中,那么变量的值始终为最后一个值。</p><p>如果要强制返回预期的结果(5,0,1,2,3,4),怎么办???</p><p>加个闭包</p><p>方法1:立即执行函数</p><p>把值传参给一个自执行的函数,函数具有块级作用域</p><pre><code>for (var i = 0; i < 5; i++) { ((num) => { setTimeout(() => { console.log(num); }, 1000); })(i); } console.log(i) </code></pre><p>方法2:setTimeout传参</p><p>setTimeout被遗忘的第三个参数,定时器启动时候,第三个以后的参数是作为第一个func()的参数传进去。</p><pre><code>for (var i = 0; i < 5; i++) { setTimeout((j) => { console.log(j); }, 1000, i); } console.log(i) </code></pre><p>方法3:使用ES6中的let</p><p>let具有块级作用域,所以外面的会报错,未定义该变量,在这儿行不通</p><pre><code>for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 1000); } console.log(i) // i is not defined </code></pre><p>方法4:函数调用</p><pre><code>var output = function (i) { setTimeout(function() { console.log(i); }, 1000); }; for (var i = 0; i < 5; i++) { output(i); // 这里传过去的 i 值被复制了 } console.log(i) </code></pre><p>本文装转自<span class="external-link"><a class="no-external-link" href="https://wsydxiangwang.github.io/web/Base/3.html" target="_blank"><i data-feather="external-link"></i>https://wsydxiangwang.github.io/web/Base/3.html</a></span></p><p>用于记录学习</p> 猜你想看 Vue路由 关于设计API接口 使用nginx反代jsdelivr nux2对比nuxt3 jQuery实现选项卡 开学啦 react学习-JSX(二) 每日一学:PHP 中的array_combine函数详解 每日一学:PHP 中的array_udiff_uassoc函数详解 Vue+axios判断用户名是否被占用 最后修改:2022 年 06 月 05 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏
4 条评论
谢谢博主分享
谢谢博主分享
滴!访客卡!请上车的乘客系好安全带,现在是:2021/10/8上午10:48:30