你不知道的javascript--上卷--读书笔记2

author author     2022-08-26     697

关键词:

  • 闭包是什么?

  答:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。通俗地来说:函数可以嵌套在其他函数中定义,这样它们就可以访问它们被定义时所处的作用域中的任何变量,这就是JavaScript的闭包。

  • 闭包有哪些应用?

  答:函数作为返回值:

function foo() {
var a = 2;
function bar() {   //bar拥有涵盖foo作用域的闭包,并对它保持了引用
console.log( a );        
}
return bar;
}
var baz = foo();
baz(); // 2

  函数作为参数进行传递:

function foo() {
var a = 2;
function baz() { //baz拥有涵盖foo作用域的闭包,并对它保持了引用
console.log( a ); // 2
}
bar( baz );
}
function bar(fn) {
fn();
}
foo();

本质上无论何时何地,如果将函数(访问它们各自的词法作用域)当作第一级的值类型并到处传递,你就会看到闭包在这些函数中的应用。在定时器、事件监听器、 Ajax 请求、跨窗口通信、Web Workers 或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是在使用闭包!

  • 闭包有哪些作用?

  答:闭包可以访问函数内部的变量;可以让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在;可以封装对象的私有方法和私有属性,实现模块化。

  循环和闭包

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

结果:输出5个6;

上述代码中,我们的预期是分别输出数字 1~5,每秒一次,每次一个,但实质上却输出了5个6;为什么会这样?

6是循环结束时 i 的最终值,这个不难理解,但为什么会是5个6呢?根据作用域的工作原理,首先声明一个i变量,然后进行迭代,每次迭代对i进行LHS操作,接着定义一个延迟1S输出函数,对i进行RHS操作,看起来好像没什么问题,实质上呢?各个迭代的函数共享同一个i的引用,在执行过程中,循环快还是延迟输出快?由结果不难推知,循环快。由此,私以为执行过程可以与下述代码等效:

var i= 6;
setTimeout( function timer() {
console.log( i );   //6
}, i*1000 );
setTimeout( function timer() {
console.log( i );    //6
}, i*1000 );
setTimeout( function timer() {
console.log( i );   //6
}, i*1000 );
setTimeout( function timer() {
console.log( i );    //6
}, i*1000 );
setTimeout( function timer() {
console.log( i );    //6
}, i*1000 );

 

如此看来问题就很简单了,在循环的过程中每个迭代我们都需要一个闭包作用域。

在这之前,我们需要了解一些概念:

函数声明: function aaa(){}  

函数声明虽然可以实现函数作用域的创建,但由此也带来了一个问题,就是全局变量的污染(aaa 被绑定在所在作用域中)和必须显示的调用这个函数才能执行其中的代码。那么怎么才能同时解决这两种问题呢?

立即调用函数表达式: (function aaa(){})() ;   或者  (function aaa (){}());

  由于函数被包含在一对 ( ) 括号内部,因此成为了一个表达式,通过在末尾加上另外一个 ( ) 可以立即执行这个函数,

  区分函数声明和表达式最简单的方法是看 function 关键字出现在声明中的位 置(不仅仅是一行代码,而是整个声明中的位置)。如果 function 是声明中 的第一个词,那么就是一个函数声明,否则就是一个函数表达式。

ok,言归正传,上面说到,在循环的过程中每个迭代我们都需要一个闭包作用域。而立即调用函数表达式会通过声明并立即执行一个函数来创建作用域。所以我们可以将上述循环改写成这样:

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

这样可以吗?不可以,虽然每次迭代我们都创建了一个新的作用域,但这个作用域是空的,没有任何变量来存储迭代中i的值。所以我们还需要声明一个变量:

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

还有其它方法吗?有,在块作用域那里说过ES6中的:let;let可以将声明的变量绑定到所在的任意的作用域内,也可以说将一个块转换成一个可以被关闭的作用域。比如这样:

for (var i=1; i<=5; i++) {
let j = i; // 是的,闭包的块作用域!
setTimeout( function timer() {
console.log( j );
}, j*1000 );
}
或者
for (let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
请记住:for循环中let声明,会在每一次迭代中都声明变量,且每次迭代都会使用上一次迭代的结束值来初始化变量。
  • 模块:

  模块的一般形式:创建对象的私有属性和私有方法,然后通过闭包创建一个能够访问对象私有属性和方法的特权方法,最后返回这个函数或者把它保存到能够访问到的地方。

  模块模式具有两个必要条件:

  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

 

你不知道的javascript--上卷--读书笔记1

作用域是什么?  答:在《你不知道的javascript》书中提到,作用域就是根据名称查找变量的一套规则。古语有“无规矩不成方圆”,但是没有方圆,规矩又给谁用?所以个人理解作用域就是“规矩”+”方圆“。作用域是在创... 查看详情

你不知道的javascript--上卷--读书笔记2

...以访问它们被定义时所处的作用域中的任何变量,这就是JavaScript的闭包。闭包有哪些应用?  答:函数作为返回值:functionfoo(){vara=2;functionbar(){//bar拥有涵盖foo作用域的闭包,并对它保持 查看详情

javascript中的this—你不知道的javascript上卷读书笔记

this是什么?this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。当一个函数被调用时,会创建一个活动记录(有时... 查看详情

你不知道的javascript(上卷)读书笔记之二----词法作用域

...要的工作类型,一种是词法作用域,一种是动态作用域,Javascript采用的是词法作用域,关于动态作用域的有兴趣的可以自行Google。1.词法阶段         首 查看详情

你不知道的javascript上卷-读书笔记-第2章词法作用域-2.2欺骗词法(代码片段)

你不知道的JavaScript上卷-读书笔记-第2章词法作用域-2.2欺骗词法作用域`eval`和`with`的缺点作用域JavaScript在ES6以前只有函数作用域。ES6开始支持块作用域:通常就是包裹的范围作用域中查找变量or函数的规则是从当前向... 查看详情

你不知道的javascript上卷-读书笔记-第2章词法作用域-2.2欺骗词法(代码片段)

你不知道的JavaScript上卷-读书笔记-第2章词法作用域-2.2欺骗词法作用域`eval`和`with`的缺点作用域JavaScript在ES6以前只有函数作用域。ES6开始支持块作用域:通常就是包裹的范围作用域中查找变量or函数的规则是从当前向... 查看详情

读书笔记你不知道的javascript(上卷)--作用域是什么

...1、理解作用域几个名词的介绍引擎:从头到尾负责整个JavaScript程序的编译及执行过程编译器:负责语法分析及代码生成器等脏活累活作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严... 查看详情

读书笔记《你不知道的javascript(上卷)》——第二部分this和对象原型(代码片段)

文章目录第6章行为委托6.1面向委托的设计6.1.1类理论6.1.2委托理论1.互相委托(禁止)2.调试6.1.3比较思维模型6.2类与对象6.2.1控件“类”ES6的class语法糖6.2.2委托控件对象6.3更简洁的设计反类6.4更好的语法反词法6... 查看详情

《你不知道的javascript上卷》学习笔记(代码片段)

第一部分:作用域和闭包一、作用域1.作用域:存储并查找变量的规则2.源代码在执行之前(编译)会经历三个步骤:分词/此法分析:将代码字符串分解成有意义的代码块(词法单元)解析/语法分析:将词法单元流转换成抽象语... 查看详情

你不知道的javascript中,读书笔记

七种内置类型null,undefined,boolean,number,string,object,symboltypeofnull===‘object‘//truenull是typeof是object的唯一的假值typeoffunction会返回‘function‘使用typeofx!==‘undefined‘比直接判断x更加安全,因为不会引发referenceerror 查看详情

你不知道的javascript(上卷)小结

上卷主要讲了作用域、闭包、this以及原型方面的内容。整体在github上瞥了一眼了原版的ydkjs,到目前修改篇幅有点大了,this和原型部分的目录已经不见了,应该是改动不少。说说本书的小缺点,一是,有些东西已经和实际不一... 查看详情

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

<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>你不知道的javascript(上卷)</title></head><body></body></html>   查看详情

你不知道的javascript(上卷)pdf

...sp; 内容简介  · · · · · ·JavaScript语言有很多复杂的概念,但却用简单的方式体现出来(比如回调函数),因此,JavaScript开发者无需理解语言内部的原理,就能编写出功能全面的程序;就像收音机... 查看详情

你不知道的javascript(上卷)

第一部分作用域和闭包第1章作用域是什么  1.1编译原理  1.2理解作用域    1.2.1演员表    1.2.2对话    1.2.3编译器有话说    1.2.4引擎和作用域的对话    1.2.5小测验  1.3作用域嵌套  1.4异常  1... 查看详情

读书笔记-你不知道的js中-promise

继续填坑模式  考虑下面的代码:functionfn(x){//dosomethingreturnnewPromise(function(resolve,reject){//调用resolve(..)和reject(...)});}varp=fn(2);  newPromise(..)模式通常称为revealingconstructor。传入函数会立即执行(不会像then(..)中的回调一样异步延 查看详情

读书笔记-你不知道的js上-对象

好想要对象···   函数的调用位置不同会造成this绑定对象不同。但是对象到底是什么,为什么要绑定他们呢?(可以可以,我也不太懂)  语法  对象声明有两个形式:  1、字面量=>varobj={...};  2、构造形式=&g... 查看详情

读书笔记-你不知道的js上-闭包与模块

闭包定义   当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。  看一段最简单的闭包代码:functionfoo(){vara=2;//闭包functionbar(){console.log(a);}returnbar;}//理论上foo执行完内部... 查看详情

《javascript设计模式》读书笔记二(封装和隐藏信息)

...你会看电视,可是你不知道电视的内部结构一样。可是在javascript中没有不论什么内置的机制。所以我们还 查看详情