当前位置: 首页 > news >正文

深入理解javascript系列(七):闭包(1)

闭包(Closures)是我学习过程中的一个瓶颈。

没有跨不过去的坎,只有走不出的心。

7.1  概念

闭包是一种特殊的现象。

它由两部分组成=>执行上下文(A),以及在该执行上下文中创建的函数(B)。

当B执行时,如果访问了A的变量对象中的值,那么闭包就会产生。

许多书籍、文章里都以函数B的名字指代这里生成的闭包。而在Chrome中,则以执行上下文A的函数名代指闭包。

我们只需知道,一个闭包对象,有A、B共同组成,在以后的篇幅中,都将以Chrome的标准来称呼。

//demo01.js
function foo() {
    var a = 20;
    var b = 30;
    
    function bar() {
        return a + b;
    }
    return bar;
}
var bar = foo();
bar();复制代码

在上面的例子中,首先执行上下文foo,在foo中定义了函数bar,而后通过对外放回bar的方式,得以让bar执行。当bar执行时,访问了foo内部的变量a和b。因此这个时候闭包就产生了。

在Chrome中通过断点调试的方式可以逐步分析该过程,从下图中可以看出,此时闭包的产生,用foo代指。


在图中,箭头所指的正式闭包。其中Call Stack为当前的函数调用栈,Scope为当前正在被执行函数的作用域链,Local为当前活动对象(AO)。

在学习了闭包的基础概念后,下面就来验证一下你是否真的理解了。现在思考一个小问题,把上面的代码稍作改动,是否形成闭包了?

//demo02.js
function foo() {
    var a = 20;
    var b = 30;
    
    function bar() {
        return a + b;
    }
    bar();
}
foo();复制代码

仍然是foo中定义的bar函数在执行时访问了foo中的变量,因此这个时候仍然会形成闭包。如图所示:


在来看一个非常有意思的例子。

//demo03.js
function add(x) {
    return function _add(y) {
        return x + y;
    }
}
add(2)(3);复制代码

对于这个既熟悉又陌生的函数,他有闭包产生吗?

当然有。当内部函数_add被返回调用时,访问了add函数变量对象中的x,这个时候,闭包就会产生,如下图所示。一定要记住,函数参数中的变量传递给函数之后也会加到变量对象中。


还有一个例子可以验证大家对于闭包的理解。

看看下面这段代码中是否有闭包产生。

//demo04.js
var name = 'window';

var p = {
    name: 'pan',
    getName: function() {
        return function() {
            return this.name;
        }
    }
}
var getName = p.getName();
var _name = getName();
console.log(_name);

复制代码

getName在执行的时候,其this是指向window对象的,而这个时候并没有形成闭包的环境,因此这个例子没有闭包。

那么如果按照下面的方式进行改动呢?

//改动一
//demo05.js
var name = "window";

var p = {
    name: 'pan',
    getName: function() {
        return function() {
            return this.name;
        }
    }
}

var getName = p.getName();

var _name = getName.call(p);    //利用call的方式改变其this指向

console.log(_name);

复制代码

//改动二
//demo06.js
var name = "window";

var p = {
    name: 'pan',
    getName: function() {
        var self = this;           //利用变量保存的方式保证其访问的是P对象
        return function() {
            return self.name;
        }
    }
}

var getName = p.getName();

var _name = getName();

console.log(_name);
复制代码

上面两处改动分别利用call与变量保存的方式保证了this的指向,那么,它们哪一个产生了闭包哪一个没有产生闭包了?这个问题,希望您与我共同思考。

这些都是我以往的学习笔记。如果您看到此笔记,希望您能指出我的错误。有这么一个群,里面的小伙伴互相监督,坚持每天输出自己的学习心得,不输出就出局。希望您能加入,我们一起终身学习。欢迎添加我的个人微信号:Pan1005919589


相关文章:

  • Spring cloud 安全部署与性能优化
  • GEF入门实例_总结_06_为编辑器添加内容
  • CIKERS Shane 20190605
  • py 6.13
  • Amazon推新送货无人机Prime Air
  • vue-music 关于playlist (底部播放列表组件)
  • 爬虫基础 2.4 会话和cookie
  • Spring boot的简单rest服务(非xml方式配置)
  • Servlet
  • Confluence 6 配置自动备份
  • 微软云端套用新模型增加精准度 减少预测模型误差
  • 【多线程系列】AQS CAS简单介绍
  • CF1063F String Journey
  • JPA(三):JPA基本注解
  • 有哪些不用编写代码就能轻松制作生成HTML5页面的工具
  • Android交互
  • conda常用的命令
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • Fastjson的基本使用方法大全
  • Idea+maven+scala构建包并在spark on yarn 运行
  • java8-模拟hadoop
  • Java小白进阶笔记(3)-初级面向对象
  • MySQL的数据类型
  • nginx 负载服务器优化
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • Redis中的lru算法实现
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 算法-插入排序
  • 算法之不定期更新(一)(2018-04-12)
  • 消息队列系列二(IOT中消息队列的应用)
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • postgresql行列转换函数
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • #在 README.md 中生成项目目录结构
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • ( 10 )MySQL中的外键
  • (3)llvm ir转换过程
  • (33)STM32——485实验笔记
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (function(){})()的分步解析
  • (八)Flask之app.route装饰器函数的参数
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (四) 虚拟摄像头vivi体验
  • (四)JPA - JQPL 实现增删改查
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .gitignore文件---让git自动忽略指定文件
  • .net 8 发布了,试下微软最近强推的MAUI