浅谈闭包

闭包 – closure, 应该可以说是javascript的一个难点吧, 其实说难也不难, 只是因为没有真正一个权威的人/书去给他一个真正的定义。 不过,学编程的人一路都要有自己的理解,很少人乐意去v死记一个定义。 自己看闭包也有很久了,但是每次回想起来又忘了自己改如何形容它, 它真的很难吗?其实并没有,每次看别人的博客,还是很快就能理清楚思路的, 于是终究还是要自己写下来,自己给自己一个理解。

苍白描述

闭包可以理解为,在函数(命名为A函数)内部创建一个内部函数,并暴露到A函数外部去(暴露方法可以是返回一个内部函数,或者将内部函数赋值给 全局/外部 变量), 然后可以通过暴露出来的内部函数,操作A函数内部的变量。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。 –阮一峰(学习Javascript闭包(Closure)

作用域(Scope)

闭包的特色是依赖于作用域实现的。 关于作用域,这里有一篇很好的公众号文章 理解JavaScript中的作用域和上下文

简单来说,每个变量被定义时,都绑定在了一个作用域中,作用域有全局的和局部的。 比如

var a = 1;
var fun1 = function () {
    var b = 1;
    var fun2 = function () {
        //...
    }

    console.log(a);//1
    console.log(fun1);//[Function]
    console.log(b);// 1
    console.log(fun2);// [Function]
}

console.log(a);//1
console.log(fun1);//[Function]
fun1();
console.log(b);// 报错 not found
console.log(fun2);// 报错 not found

上面的例子中, a、fun1 都是全局变量,在全局中声明; b、fun2 都是 fun1 内部的 局部变量, 在fun1中声明。 当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。 通过作用链域,可以决定变量的访问。 作用链域的寻找可以理解成可以向上爬寻的。 上面代码的作用链域可以展示如下

    window(全局作用域,包含 a、fun1)
      ^
      |
      |
      |
    fun1(fun1 函数内部作用域,包含b、fun2)

当 fun1的语句在内部找不到需要的变量是,就会沿着箭头向上寻找外部的作用域,如果找不到再向上,直到找到或者到了全局作用域。 但是, 箭头上面的语句却不可以向下寻找作用域,所以外部语句不能访问到内部变量(这是一般情况下)

闭包

那么怎么才能 是函数外部能够访问内部的变量呢,闭包可以做到。 引用学习Javascript闭包(Closure)的代码

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。 它一共运行了两次,第一次的值是999,第二次的值是1000。 这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。 为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1。 因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

闭包的作用

闭包的特性就在外部读取函数内部的变量。 这个特性有什么作用呢,思路是因人而异的。 比如

模拟对象的私有属性,只能通过函数内部的方法访问函数的属性 面向对象编程

可以一一衍生下去

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏架构师之旅

javascript深入理解js闭包

一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言的特殊...

24510
来自专栏程序员互动联盟

【编程基础】C++引用简单介绍

对于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&...

3228
来自专栏C/C++基础

RTTI简介

RTTI是Runtime Type Identification的缩写,是“运行时类型识别”的意思。面向对象的编程语言,象C++,Java,Delphi都提供了...

963
来自专栏用户2442861的专栏

java final 关键字

http://blog.csdn.net/niguang09/article/details/6035813

982
来自专栏牛肉圆粉不加葱

[7] - trait

这是我以前在知乎上看到关于类继承作用的回答,虽不完全正确,却十分明确的表达出了好的代码应避免类继承而尽量使用类组合。Scala 显然也非常赞同这一点,以至于有了...

1072
来自专栏积累沉淀

Python快速学习第三天

第三天: 字典 什么是字典? 字典是Python语言中唯一的映射类型。 映射类型对象里哈希值(键,key)和指向的对象(值,value)是一对多的的关系,通常被...

1958
来自专栏Android开发指南

6:异常处理

2998
来自专栏用户2442861的专栏

C++编程思想重点笔记

引申:如何在const成员函数里修改成员 —— 按位和与按成员const 如果我们想要建立一个const成员函数,但仍然想在对象里改变某些数据,这时该怎...

2031
来自专栏Vamei实验室

Java基础09 类数据与类方法

我们一直是为了产生对象而定义类(class)的。对象是具有功能的实体,而类是对象的类型分类。这是面向对象的一个基本概念。 在继承(inheritance)中,我...

1878
来自专栏C/C++基础

如何禁止函数的传值调用

按照参数形式的不同,C++应该有三种函数调用方式:传值调用、引用调用和指针调用。对于基本数据类型的变量作为实参进行参数传递时,采用传值调用与引用调用和指针调用的...

711

扫码关注云+社区

领取腾讯云代金券