美文网首页
JavaScript作用域闭包

JavaScript作用域闭包

作者: 小也_ | 来源:发表于2018-08-16 10:29 被阅读0次

词法作用域

词法作用域中使用的域,是变量在代码中声明的位置所决定的

闭包

个人理解:

  1. 闭包首先是一个函数

  2. 这个函数在一个函数作用域内(这里姑且称这个父函数为Func, 比如下方的makeAdder())被声明,可以使用作用域内的局部变量, 且保持对这个作用域的引用.

    (以上两点为定义,第3条是应用场景和产生的影响)

  3. 这个函数在Func作用域以外被调用, 如果它调用了Func作用域的局部变量,就会导致内存泄漏.

    function makeAdder(x) {
       function bar(y) {
        return x + y;
      };
        return bar;
    }
    //add5 和 add10 类型都是function ,因为makeAdder(x)返回的类型为function
    var add5 = makeAdder(5);// typeof add5 === function
    var add10 = makeAdder(10);//typeof add10 === function
    
    console.log(add5(2));  // 7
    console.log(add10(2)); // 12
    

你不知道的JavaScript(上卷) 中提及:

闭包是基于词法作用域书写代码时所产生的自然结果, 你甚至不需要为了利用它们而有意识地创建闭包。 闭包的创建和使用在你的代码中随处可见。 你缺少的是根据你自己的意愿来识别、 拥抱和影响闭包的思维环境。

定义:

当函数可以记住并访问所在的词法作用域时,就产生了闭包. 即使函数是在当前词法作用域中之外执行的.

或者:

bar()函数依然持有对makeAdder(x)作用域的引用, 而这个引用就叫做闭包.

为什么要有闭包?

MDN上的解释为:

因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

​ 也就是说, 我们可以用闭包模拟私有方法,类似于java中的中的私有方法, 而原生JavaScript没有这种支持

类型 结果
Undefined "undefined"
Null "object" 这儿有坑
Boolean "boolean"
String "string"
Symbol "symbol"
Number "number"
宿主对象(由JS环境提供) Implementation-dependent
函数对象([[Call]] 在ECMA-262条款中实现了) 函数对象([[Call]] 在ECMA-262条款中实现了)
任何其他对象 "" "object"
在循环中中使用闭包所导致的问题
function loop(){
    var arr = [];
    for(var i = 0;i<5;i++){
        arr.push(function(){
            print(i);
            //console.log(i);
        })
    }
    return arr;
}
function print(x){
    console.log(x);
}

var test = loop();
test[0]();// 5
test[1]();//5

关于这种现象, MDN的解释为:

由于循环在事件触发之前早已执行完毕,变量对象i(被三个闭包所共享)已经指向了的最后一项。

也就是5. 不过我不太明白这里为什么"循环在事件触发之前早已执行完毕"这句话. 我的粗浅分析是: 由于JS中没有块级作用域, 所有这里的for循环和arr.push(...)处于同一级作用域,而js在编译时会对loop进行函数提升, 然后执行完for循环之后i的值就变成了5. 在test[0]()处调用print()时,引擎在作用域内查找i,这个作用域就是刚刚提到的和for循环同级的作用域. 而这时for循环在loop()编译时早已执行了,所以i的值是5.

个人理解:

如果函数的调用时的当前作用域不处于声明时的当前作用域, 那么就产生了闭包. 这个当前作用域指的是函数所处的最近作用域,举例来说:

function foo(){//foo的当前作用域:全局window对象
    function bar(){//bar的当前作用域:foo
        console.log("hello");// console.log的作用域栈 bar→foo→全局(window对象), 当前作用域: bar
    }
}

所以, 总结一下我理解的闭包就是(只看加粗部分就行):
(为了解决外部作用域能访问一个函数作用域内局部变量的问题,类似java中的私有方法)

  • 我们在函数内定义一个函数,这个函数可以访问父函数的局部变量,
    (这很显然是可以访问的)
  • 这个函数也能被外部作用域调用
    (类似前面var test = loop(); test[0]();, 外部的test[0]()调用了loop的内部函数)
  • 这个函数就是闭包. 这个函数就是闭包. 对,这就是闭包
    当这个闭包被外部作用域调用时, 能够保持对父函数作用域的引用
    (就是它能一直访问局部变量啦, 哪怕父函数早已执行完毕,本应该销毁这个变量, 然后这个变量"命不该绝", 一直存在着, 所以导致了内存泄漏,所以这里就应该提及垃圾回收机制了)

相关文章

  • 2018-01-07 关于javascript闭包和作用域的理解

    关于 javascript 闭包的一些思考 作用域 词法作用域 函数作用域 块作用域 闭包 什么是作用域? 作用域...

  • 2018-07-11

    深入理解闭包: 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非...

  • 学习JavaScript闭包和作用域笔记

    JS JavaScript闭包和作用域 闭包 JavaScript高级程序设计中对闭包的定义:闭包是指有权访问另外...

  • 作用域闭包

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • JavaScript 作用域

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • js闭包问题

    javascript 闭包的概念,闭包的作用,闭包经典面试题详解(配图解) 函数作用域(闭包前置知识) 要彻底弄懂...

  • 闭包、定时器

    一、什么是闭包? 有什么作用 1.变量的作用域  要理解闭包,首先必须理解JavaScript的变量作用域。变量的...

  • JavaScript深入理解-闭包(Closure)

    推荐文章:学习Javascript闭包(Closure)- 阮一峰javascript深入理解-从作用域链理解闭包...

  • 你不可不知道的 JavaScript 作用域和闭包

    原文出处:JavaScript Scope and Closures 作用域和闭包是 JavaScript 中重要...

  • JavaScript中的闭包

    1.什么是闭包 要理解什么是闭包,就得先理解变量的作用域。在JavaScript中,有两种作用域,全局作用域和函数...

网友评论

      本文标题:JavaScript作用域闭包

      本文链接:https://www.haomeiwen.com/subject/dkfnbftx.html