资讯专栏INFORMATION COLUMN

js函数闭包了解一下

Forelax / 2822人阅读

摘要:问题匿名函数的执行具有全局性,所以闭包函数的一般指向,因为里面的闭包函数是在作用域下执行的,也就是说,指向可以改写成如下,内存泄漏问题如果闭包在作用域链中保存着元素,则该元素内存将无法自动销毁。

介绍你下你理解的闭包?不管怎样!我最近听到很多次!感觉是不好好总结一下没法面对那些犀利的追问!
如果觉得闭包理解的很透彻,就直接跳到最后看题目!

1.闭包概念

小红书的解释闭包是有权访问另一个函数作用域中的变量的函数。明白了吗?就是一个函数,一个可以访问其他函数中变量的函数。所以常见的创建闭包的方式就是在一个函数内部创建另一个函数。

function bag(num){
    return function(){
        return num
    }
}
var bagc = bag(12)
console.log(bagc()) //12

可以看到在bag内部的匿名函数可以访问外部bag函数的变量num。

2.闭包的用处

闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中

function f1(){

     var n=999;

     nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

}

var result=f1();

result(); // 999 

nAdd(); //变量n被保存了

result(); // 1000

上面是阮一峰在文档中的一个例子,读取函数内部变量我觉得用处一般吧,让变量保持在内存中的用处倒是不少,像经常使用的that=this等。下面看一个常见的问题:

 for(var i = 0;i <10;i++){
     setTimeout(()=>{
        console.log(i)
     },1000)
  }
  //上面的代码我们希望按照索引值打印,结果却打印了10个10,为什么就不解释了,i是全局变量。
  //换成下面的写法,就能解决问题,正是因为闭包 让变量的值始终保持在内存中,每个i都存在了num这个局部变量中    
        
  for(var i = 0;i <10;i++){
      (function(num){
         setTimeout(()=>{
            console.log(num)
         },1000)
       })(i)
   }
3.使用闭包需要注意的点

闭包虽然在解决一些问题上有好处,但是由此引发的一些问题要注意,而且由于闭包会携带外部函数作用域,所以内存占用比较大,所以尽量少用、慎用闭包。

1.变量问题

正是因为闭包可以使用外部变量,所以下面的代码中,返回的匿名函数中对变量i的使用将会是最终的值,数组中存放的函数的返回值将都会是10。

function test() {
   var result = [];
   for(var i = 0; i<10; i++){
      result.[i] = function () {
         return i;
      }
   }
   return result
}

需要将上述代码改写成如下:

function test() {
   var result = [];
   for(var i = 0; i<10; i++){
      result.[i] = function (num) {
         return function() {
           console.info(num);  
         }
      }(i)
   }
   return result
}

此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样。

2.this问题

匿名函数的执行具有全局性,所以闭包函数的this一般指向window;

var object = {
     name: "object",
     getName:function() {
        return function() {
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows

可以改写成如下:

var object = {
     name: "object",
     getName:function() {
        var that = this;
        return function() {
             console.info(that.name)
        }
    }
}
object.getName()()    // object
3.内存泄漏问题

如果闭包在作用域链中保存着html元素,则该元素内存将无法自动销毁。

function  showId() {
    var el = document.getElementById("app")
    el.onclick = function(){
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
}

// 改成下面
function  showId() {
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
    el = null    // 主动释放el
}
4.闭包练习题

好了,看到这里是不是感觉对闭包理解的很到位了?别着急,看看这两个小问题测试一下!

1.与函数调用结合
var Test = {
    close:function(val){
        return function (z){
            return ++ val +z
        }
    }
}
var getClose = function(val){
    return Test[val]
}                         
var fn = getClose("close")
var cover = fn(100)
console.log(cover(200)) 
console.log(cover(300))
console.log(fn(100)(200))
console.log(fn(100)(200))
console.log(getClose("close")(100)(300))

//输出结果见结尾处
2.与dom结合
var container1 = document.getElementById("container1")
var container2 = document.getElementById("container2")
var container3 = document.getElementById("container3")
var container4 = document.getElementById("container4")
var container5 = document.getElementById("container5")

var innerHTML = "window的html"
var events = {
    innerHTML:"我是events",
    getHtml:function (){
        console.log(this.innerHTML)
    },
    setFun:function(){
        return this.getHtml
    },
    proxy:function(){
        var self = this;
        return function(){
            self.getHtml()
        }
    }
}
container1.onclick = events.getHtml; 
container2.onclick = events.setFun();
container3.onclick = events.proxy();
container4.onclick = function(){
    window.setTimeout(events.setFun(),0)
}
container5.onclick = function(){
    window.setTimeout(events.proxy(),0)
}

还ok?有没有被绕晕!晕了就打开电脑敲吧

看一下输出结果吧
第一题:401 402 301 301 401
第二题:container container2 我是events window的html 我是events









文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106511.html

相关文章

  • 前端基础进阶(六):在chrome开发者工具中观察函数调用栈、作用域链与闭包

    摘要:在的开发者工具中,通过断点调试,我们能够非常方便的一步一步的观察的执行过程,直观感知函数调用栈,作用域链,变量对象,闭包,等关键信息的变化。其中表示当前的局部变量对象,表示当前作用域链中的闭包。 showImg(https://segmentfault.com/img/remote/1460000008404321); 在前端开发中,有一个非常重要的技能,叫做断点调试。 在chrome...

    draveness 评论0 收藏0
  • 闭包不能吃...

    摘要:什么是闭包闭包是函数废话闭包还是一个可以访问函数中变量的函数。每个闭包都是引用自己词法作用域内的变量。每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。 为什么要写深入理解 笔者并不是大神,只是一个在校的大三学生。开始写深入理解系列是为了给js的一些重难点知识进行梳理,而不是每次面试之前都将这些知识重...

    stonezhu 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0
  • 一次搞定this和闭包

    摘要:他的组成如下对的就是你关注的那个变量对象作用域链跟闭包相关由于是单线程的,一次只能发生一件事情,其他事情会放在指定上下文栈中排队。 闭包和this,是两个相当高频的考点,然而你有没有想过,实际上他们两个都跟同一个知识点相关? 有请我们的这篇文章的主角,执行上下文 执行上下文 执行上下文是什么 可以简单理解执行上下文是js代码执行的环境,当js执行一段可执行代码时,会创建对应的执行上下文...

    Airy 评论0 收藏0
  • 10个流行的JavaScript面试题

    摘要:然而,异步函数不会立即被推入调用堆栈,而是会被推入任务队列,并在调用堆栈为空后执行。将事件从任务队列传输到调用堆栈称为事件循环。我们调用接受和或返回另一个函数称为高阶函数的函数。 为了保证可读性,本文采用意译而非直译 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 1.如何理解 JS 中的this关键字? JS 初学者总是对 this 关键字感到困惑,因为与其他现...

    CollinPeng 评论0 收藏0

发表评论

0条评论

Forelax

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<