读书笔记《你不知道的JavaScript上卷》1.5作用域闭包

《JavaScript高级程序设计》读书笔记 【1~7章】 文章目录1.Javascript简介1.1. ECMAScript1.1.1. ECMAScript简介1.1.2. ECMAScript兼容1.2. 文档对象类型DOM1.2.1. DOM简介1.2.2. DOM级别1.2.3. 其他DOM标准1.3. 浏览器对象类型BOM2. HTML中使用JavaScript2.1. < script >元素3. 基本概念3.1. 语法3.2. 数据类型3.3. 流控制语句3.4. 理解函数 1.Javascript简介 JavaScript是一种专为与网 阅读详情

5.1 闭包的概念

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

这是闭包的定义,对于一个作用域(就比如函数所形成的作用域)来说,通常情况下,当执行完这个函数以后,JS引擎的垃圾回收机制就可能会回收掉这个函数所占用的内存,但是如果这个函数形成了闭包那么它就不会回收掉这个函数所占用的内存了。
举个简单的例子:

function foo() {
    var a = 2;
    function bar() {
        console.log( a );
    }
    return bar;//这里bar被返回去了,所以bar是不会被垃圾回收机制回收掉的,所以产生了闭包
}
var baz = foo();
baz(); //这个地方已经在函数foo的作用域外面了,但是仍然可以访问函数内部的东西

无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
上面使用return是一种最常见的形成闭包的方式,还有一种常用的方式就是回调函数:

function foo() {
    var a = 2;
    function baz() {
        console.log( a ); // 2
    }
    bar( baz );//这里把baz当做参数传进去了
}
function bar(fn) {
    fn(); // 所以在这里其实是执行了foo中的baz,也就是bar作用域调用了另外一个作用域foo中的东西,所以也产生了闭包
}

只要使用了回调函数,实际上就是在使用闭包,我们常用的setTimeout函数其实就是一个闭包,这里就不再重复了。
综上,闭包并不是什么高大上的东西,我们有意或者无意肯定使用过了好多闭包。

5.2 闭包的功能

闭包有两大功能:

  • 1.访问局部变量
  • 2.变量所占的内存不被释放,以实现数据共享

其中第二点有同样会产生一个问题就是内存溢出,所以使用闭包时要小心。

5.3 闭包与循环

有一个经典的不能再经典的面试题,就是分别输出1~5,每一秒执行一次,每次一个,现在考虑如下代码:

for (var i=1; i<=5; i++) {
    setTimeout( function timer(){
        console.log( i );
    }, i*1000 );
}

它执行结果是每秒打印一个数字,打印的数字全部都是6。为什么会产生这样的情况呢?
我们知道setTimeout里面的函数timer是一个回调函数,它并不会立即执行,而是等到相应的时间到了才会执行,每次循环的时候都会启动这么一个延迟函数,让他分别在1~5秒后执行函数timer,但是当回调函数timer执行的时候这个循环早就结束了,而timer中引用的i是循环中的i,循环结束后i的值是6,所以都会打印6。其实这里如果把循环的时间设置成0,同样的也会打印出5个6,因为JS是单线程的(不考虑新特性),当调用setTimeout时他会把回调函数放在一个新的调用栈中,然后等线程空闲了,它才会在相应的时间去处理回调函数,而如果时间是0的话,那么线程把回调函数放入栈后,线程并没有空闲而会继续执行setTimeout后面的语句,并没有立刻执行回调方法。
那么怎么样才能使得这个功能正常工作呢?

for (var i=1; i<=5; i++) {
    (function(){
        var j = i;
        setTimeout( function timer(){
            console.log( j );
        }, j*1000 );
    })();//使用自调用函数产生一个新的作用域,并定义一个临时变量接收i
}

其实除了上面这种形式意外还有一种形式,下面这种方式直接传递参数进去,代码更加简洁:

for (var i=1; i<=5; i++) {
    (function(j){
        setTimeout( function timer(){
            console.log( j );
        }, j*1000 );
    })( i );
}

在ES6中引入了let它会形成作用域,可以更好的解决这个问题:

for (let i=1; i<=5; i++) {//注意这里使用的是let不是var
    setTimeout( function timer(){
        console.log( i );
    }, i*1000 );
}

5.4 模块

5.4.1 经典模块机制

首先我们直接看代码吧:

function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];

    function doSomething() {
        console.log( something );
    }

    function doAnother() {
        console.log( another.join( " ! " ) );
    }

    return {
        doSomething: doSomething,
        doAnother: doAnother
    };
}

var foo = CoolModule();

foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

这几行代码很容易看懂,函数CoolModule有return,形成了闭包,而CoolModule其实就是一个模块。这样做的好处就是屏蔽了内部的属性,并且向外暴露了接口,可以有效的解决无意中产生的变量名重复等问题。这个模式在JavaScript中被称为模块。
模块的两个必要条件:

1.必须有外部的封闭的函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。
2.封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域形成闭包,并且可以访问或者修改私有的状态。

上面的这种模块是可以创建多个模块实例,更多情况下我们只需要创建一个模块实例,如下:

var foo = (function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];

    function doSomething() {
        console.log( something );
    }

    function doAnother() {
        console.log( another.join( " ! " ) );
    }

    return {
        doSomething: doSomething,
        doAnother: doAnother
    };
})();//利用自调用函数创建唯一一个对象。

foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

如果我们把变量foo命名为$,里面函数是对DOM做一些操作,那么这不是就和JQuery类似了吗?其实,JQuery就是引用了模块机制。

5.4.2 现代模块机制

现在模块机制将不作为重点,这里直接给出一些代码,有兴趣的读者可以参考seaJS,RequireJS等模块化类库。

var MyModules = (function Manager() {
    var modules = {};

    function define(name, deps, impl) {
        for (var i=0; i<deps.length; i++) {
            deps[i] = modules[deps[i]];
        }
        modules[name] = impl.apply( impl, deps );
    }

    function get(name) {
        return modules[name];
    }

    return {
        define: define,
        get: get
    };
})();

上面写了一个可以定义模块的模块,他是定义其他模块的入口。

MyModules.define( "bar", [], function(){//这里定义了一个模块bar
    function hello(who) {
        return "Let me introduce: " + who;
    }

    return {
        hello: hello
    };
} );

MyModules.define( "foo", ["bar"], function(bar){//这里定义了一个模块foo
    var hungry = "hippo";

    function awesome() {
        console.log( bar.hello( hungry ).toUpperCase() );
    }

    return {
        awesome: awesome
    };
} );

var bar = MyModules.get( "bar" );//获取模块bar
var foo = MyModules.get( "foo" );//获取模块foo

console.log(
    bar.hello( "hippo" )
); // 模块bar调用方法
foo.awesome(); //模块foo调用方法
5.4.3 未来模块机制

未来模块机制就是ES6自带的export和import,有兴趣的可以参考阮一峰的ES6相关文章。

SuccessFactors入门篇 SuccessFactors入门篇—— Employee Central(一)最近通过一个月左右的学习,拿到了SF EC(SuccessFactors Employee Central )模块SAP认证,所以打算把自己学习SF的整个过程以及相关资料和大家分享一下,相互切磋,共同进步。Employee Central简单了解Employee Central简单了解新的改变功能快捷键合理的创建标题,有... 阅读详情

相关推荐

ICC II 时钟树综合(CTS)前奏:从约束定义到NDR规则的全方位设置指南

本文详细介绍了ICC II中时钟树综合(CTS)的前期准备工作,包括约束定义、NDR规则设置和时钟平衡点控制等关键步骤。通过实际案例和代码示例,指导工程师如何优化时钟偏斜、插入延迟和信号质量,确保芯片设计的时序收敛和性能稳定。特别强调了非默认布线规则(NDR)在时钟网络设计中的重要性。

weixin_42530458的博客 212

《你不知道的JavaScript》(上卷)读书笔记:作用域和闭包1.5

提升 函数作用域和块作用域的行为是一样的,可以总结为:任何声明在某个作用域内的变量,都将附属于这个作用域。 但是,作用域同其中的变量声明出现的位置有某种微秒的联系。 “先有鸡还是现有蛋” 直觉上认为,js代码在执行时是由上到下一行一行执行的,但是实际上并不完全正确。典型代码如下所示: a=2; var a; console.log(a);//2 这段代码的运行...

qq_34241037的博客 203

从零构建NVENC编码器:一个游戏开发者的实战手册

本文详细介绍了如何从零构建NVENC编码器,特别针对游戏开发者提供实战指南。内容涵盖NVENC基础概念、DirectX纹理捕获、异步编码优化及高级特性配置,帮助开发者高效集成硬件编码技术到游戏引擎中,实现高性能游戏录制和直播功能。重点解析了NVIDIA专用编码芯片的优势与API使用技巧。

weixin_29292431的博客 366

《你不知道的JavaScript上卷》知识点整理与读书笔记

第一部分 作用域和闭包 第1章 作用域是什么 1.1编译原理 1.2理解作用域 1.3作用域嵌套 1.5异常 第2章 词法作用域 第3章 函数作用域和块作用域 第5章 作用域和闭包 第二部分 this和对象原型 第1章 关于this 第2章 this全面解析 第3章 对象 第4章 混合对象“类” 第5章 原型 第6章 行为委托 之前被好友推荐过《你不知道的JavaScript》这一系列的书籍。上中下三本书都不算厚,内容也是比较独立。本来是打算一个月内看完这本上卷和下卷,可总是因为自己的.

qq_45549336的博客 6405

GoPro官方API实战:从蓝牙配对到Wi-Fi流媒体,构建跨平台控制应用

本文详细解析了GoPro官方API的开发实践,涵盖蓝牙配对、Wi-Fi流媒体控制等关键技术。通过实战案例,指导开发者如何构建跨平台控制应用,解决设备发现、指令解析、视频流传输等核心问题,并分享Android平台迁移经验与常见问题排查方法。

weixin_30727835的博客 397

Surface Go 2 变身 Linux 开发本:保姆级 Ubuntu 20.04 双系统安装与驱动配置全攻略

本文详细介绍了如何将 Surface Go 2 变身为高效的 Linux 开发本,涵盖 Ubuntu 20.04 双系统安装、专用内核配置、驱动优化等全流程。通过 linux-surface 内核安装和硬件驱动优化,确保 Surface Go 2 的触控、笔输入、摄像头等功能完美运行,适合开发者打造便携生产力工具。

weixin_30596165的博客 616

【读书笔记】《你不知道的JavaScript(上卷)》——第一部分 作用域与闭包

文章目录第1章 作用域是什么1.1 编译原理1.2 理解作用域1.3 作用域嵌套1.4 异常第2章 词法作用域 github:https://github.com/getify/You-Dont-Know-JS/tree/1ed-zh-CN gitee:https://gitee.com/OliverDaDa/You-Dont-Know-JS —— forked from github 第1章 作用域是什么 1.1 编译原理 相对来说JavaScript并不能像其他编译语言一样,可以将编译结果直接作

程序边界 786

MONAI教程<1>-安装

MONAI的安装非常简单,常用的有两种方法: 直接 pip install monai 从GitHub 上安装 monai是通常配合其他库一起使用的,比如pytorch, nibabel, skimage, pillow等等。缺什么直接pip install 就行

Tina姐的博客 1万+

你不知道的JavaScript(上卷)读书笔记

《你不知道的JavaScript(上卷)》读书笔记。

多啦的博客 865

Android BSP 开发深度解析:驱动开发、系统定制与调试实战

本文系统介绍了Android BSP开发的核心技术要点,重点探讨了外设驱动开发与调试方法。文章首先解析了Android系统分层架构和BSP的关键作用,详细阐述了Linux内核驱动开发基础,包括字符设备、平台设备和输入子系统驱动的实现方法。随后针对触摸屏、WIFI、蓝牙、USB、摄像头和屏幕等常见外设,深入分析了驱动开发要点和调试技巧。此外,还梳理了Android系统启动流程,介绍了常用调试工具和方法论,并提供了面试常见问题及参考答案。全文内容全面实用,为Android底层开发人员提供了系统的技术指南。

郑伟强dev的专栏 293

多思计组实验实验六 微程序控制器实验

实验六 微程序控制器实验

qq_53089329的博客 3789

你不知道的JS(上卷)——读书笔记5 作用域闭包

第五章 闭包在JS中无处不在,我们需要的是能够识别、理解并能灵活运用它 function foo(){ var a = 2; function bar(){ console.log(a); //2 } bar(); } 在上述代码中,是一个属于闭包的简单例子,但是并不能最好的代表闭包所表现出来的作用,借用书中的一句话: 这是闭包吗?技术上来讲,也许是。但根据前面的定义,确切地说并不是。我认为最准确地用来解释bar()对a的引用的方法是词法作用域的查找规则,而这些规则只是闭包的一部分。(但却

weixin_44710964的博客 213

AI 赋能 DBA:如何用 DeepSeek 等大模型简化数据库管理工作

数据库管理员(DBA)的工作涉及 SQL 优化、故障排查、性能监控等复杂任务。而 DeepSeek、ChatGPT 等大模型可以大幅减少重复劳动,提高 DBA 的工作效率。:某电商平台的订单查询 SQL 执行缓慢(平均 5s),DBA 需要优化。:DBA 需要监控 MySQL 的慢查询,但不想手动写脚本。:某金融系统频繁出现数据库死锁,DBA 需要快速定位原因。:大模型可分析 SQL 执行计划,推荐索引优化方案。:用日常语言查询数据库,无需写复杂 SQL。:一键生成监控、备份、数据迁移脚本。

专注于编程、AI、人工智能等多个领域内容研究和分析 565

《你不知道的JavaScript上卷》知识点整理与读书笔记_百度你不知道的js书知识

/也就是这个对象本身,想一想为什么this是指向这个对象本身,我保证前面的this里面讲的知识,绝对可以分析出来这里的this指向哪里。foo.call(obj)//2 这里显示调用,foo中this是obj,所以回调中是obj的a。//这行代码只是为了验证()中的var i,以及{}中的a,最后在外部均可以访问到这两个标识符。foo()//3 这里光秃秃调用,foo中this是window,所以回调中是window的a。//当然把最后的()放进去的效果也是一样的,仅仅是书写风格不同。

m0_61067876的博客 1146

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

《你不知道的JavaScript》(上卷)读书笔记:作用域和闭包1.6->闭包->No.2

看一段代码: var a=2; (function IIFE(){ console.log(a); })(); 虽然这段代码可以正常工作,但是它严格来讲并不是闭包。 因为函数IIFE并不是在它本身的词法作用域以外执行的。它在定义时所在的作用域中执行,实际效果与下段代码相同: function IIFE2(){ console.log(a); }; IIFE2(); a是通过普通的词法...

qq_34241037的博客 231

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

《你不知道的JavaScript》--读书笔记

???? 上卷: 作用域和闭包, this和对象原型 ???? 中卷: 类型和语法, 异步和性能 ???? 下卷:起步上路,es6及更新版本 目录 Part 1 作用域和闭包 chart 1 作用域是什么 1.1 编译原理 1.2 理解作用域 1.3 作用域嵌套 1.4 异常 1.5 ????小结 chart 2 词法作用域 2.1 词法阶段 2.2 欺骗词法 2.3 ????小结 Part 1 作用域和闭包 chart 1 作用域是什么 1.1 编译原理 javas

一只胖胖胖miao 974

【读书笔记】《你不知道的 JavaScript(上卷)》

第一部分 作用域和闭包 1.1 作用域是什么? 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。赋值操作符会导致 LHS 查询。=操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。 JavaScript 引擎首先会在代码执行前对其进行编译(词法分析->语法分析...

日常问题bug解决、学习分享、个人杂谈等等随便写写哈哈哈 167

你不知道的JS读书笔记1—闭包&作用域

编译原理编译原理,实际上JavaScript是编译语言,只是它在执行前的短暂时间快速的编译。一般的编译步骤包括: 词法分析:简单地说就是划分单词 语法分析:将这些单词进行分析,转化为“抽象语法树”(AST) 代码生成:将“抽象语法树”变成可执行的代码

野草园 652

《你不知道的JavaScript(上卷)》第一部分:作用域与闭包的读书笔记

《你不知道的JavaScript(上卷)》第一部分:作用域与闭包的读书笔记 作用域和闭包 1、介绍了作用域,主要说明了RHS和LHS这两个概念。RHS是读取值,LHS是赋值。 2、词法作用域:有两个机制可以动态改变词法作用域:eval和with。eval可以运行字符串代码,动态修改已经存在的词法作用域。with可以在属性不存在的时候,将此属性泄漏到全局作用域 3、介绍了词法作用域里面的函数作用域和块作用域。 函数作用域本质上是隐藏函数内部的变量和函数,符合最小暴露原则。 块作用域必须要使用let关键字才能生

Czuaphe的博客 483

[ffxixslh] 你不知道的JavaScript - 作用域和闭包 - 读书笔记 (1)

分词/词法分析(Tokenizing):将由字符组成的字符串分解成有意义的代码块,这些代码块称为词法单元(token)解析/语法分析(Parsing):将词法单元流(数组)转换成“抽象语法树”(Abstract Syntax Tree, AST)代码生成:将 AST 转换为可执行代码。

aahape的博客 213

JavaScript闭包读书笔记

JavaScript闭包读书笔记 // 作用域链:一个对象列表。 // 每次调用javascript函数的时候,都会为其创建一个对象来保存局部变量,并把这个对象添加到作用域链中,当函数返回的时候,再将这个绑定的作用域链删除。 // 闭包可以捕捉到局部变量和参数,并且一直保存下来 var scope = "global scope"; function checkscope() { var ...

asdf_123123的博客 220

读书笔记(你不知道的javascript上卷)(上)

本篇作为自己已经看了一半的你不知道的javascript上卷的一些小节,重新认识js,希望我的一些理解能够给大家重新认识js。前半部分的内容主要有以下几点 作用域和闭包 作用域 词法作用域 函数作用域和块作用域 作用域闭包 首先对于一段js源代码,js引擎执行分为了三个步骤 词法分析 语法分析 代码生成 虽然引擎编译的步骤只有三步,但是千万不要以为js编译非常简单,实际实现的过程是非常复...

Ningqiugu的博客 490

JS闭包—你不知道的JavaScript上卷读书笔记(二)

关于闭包,初学者会被绕的晕头转向,在学习的路上也付出了很多精力来理解。 让我们一起来揭开闭包神秘的面纱。 闭包晦涩的定义 看过很多关于闭包的定义,很多讲的云里雾里,晦涩难懂。让不少人以为闭包是多么玄乎的东西。在我看过的所有书籍中,我更喜欢《你不知道的javascript(上卷)》的定义: 当函数可以记住并访问所在的词法作用域时,就产生了闭包,或者说函数在创建时的词法作域之外执行。 通俗的来说(不严...

weixin_30240349的博客 107

读书笔记:JavaScript——闭包

闭包:

Diana24407的博客 257

【JavaScript忍者秘籍】读书笔记之第二部分:函数的定义与参数、函数调用、闭包和作用域

【JavaScript忍者秘籍】读书笔记之第二部分:函数的定义与参数、函数调用

QAQ 1613

面试官问题之什么是JavaScript闭包?回答技巧及正确答案[图]

闭包,有人说它是一种设计理念,有人说所有的函数都是闭包。到底什么是闭包?这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。 这个问题也有很多朋友在公众号给李老师留言了,问题表达方式不一样,都是终归到一点,就是对闭包没有很清晰的理解。大家经常去网上找相关资料,但是对闭包的说法都是各种各样的,让大家对闭包的定义没有一个概念。 所以今天我们来一起讲讲什么是闭包,帮助大家理解,今天的内容可以直接收藏起来。方便以后看。 什么是闭包(Closure) 简单讲,闭包就是指有权访问另一个函数作

minemi的博客 1132
上一篇: 读书笔记《你不知道的JavaScript上卷》1.4提升
下一篇: CSS改变input光标颜色
javao_0
博客等级 码龄12年 6粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值