js函数(4)闭包
8.6闭包
背景:3.10 变量作用域
在函数体内,局部变量的优先级高于同名的全局变量。如果在函数内声明一个局部变量或者函数参数中带有的变量和全局变量重名,则局部变量会覆盖全局变量;
在全局作用域编写代码时可以不写var 语句,但是声明局部变量时必须使用var语句
3.10.1函数作用域和声明提前
js中没有块级作用域,取而代之是函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
js的函数作用域值:在函数内声明的所有变量在函数体内是始终可见的。
变量在声明之前就已经可以使用---------声明提前
3.10.2作为属性的变量
使用var声明一个变量,不可以使用delete删除;不用var定义的变量则可以使用delete删除。
js中使用this关键字来引用全局对象,却没有方法引用局部变量中存放的对象。
3.10.3作用域链
类比 局部变量看做是自定义实现的对象的属性。
每一段js都有一个与之关联的作用域链:该作用域链是一个对象列表或者链表,该组对象定义了这段代码”作用域中“的变量。
当js需要查找变量x时(过程称作变量解析)
1 、它会从链中的第一个对象进行查找,如果这个对象有一个名为x的变量,则会直接使用这个属性的值
2 、如果第一个对象中不存在名为x的属性,则会继续查找链上的下一个对象。
3如果第二个对象依旧没有名为x的属性,则会继续向下查找
若是始终没有找到 则会抛出一个引用错误异常。
在js'的最顶层代码中(即不包括在任何函数定义的代码),作用域链由一个全局对象组成。
在不包含嵌套的函数体内,作用域链上有两个对象,第一个是定义函数参数和局部变量的对象,第二个是全局变量;
在一个嵌套的函数体内,作用域链上至少有三个对象。
理解对象链的创建规则:
当定义一个函数时,它实际上保存一个作用域链。
当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的”链“,当函数返回值时就从域链中将这个
绑定变量的对象删除。
对于嵌套函数来说:
每次调用外部函数时候,内部函数在每次定义的时候都有微妙的差别--------在每次调用外部函数时,内部函数的代码都是相同的,而且关联这段代码的作用域链也不相同
闭包
函数对象可以通过作用域链关联起来,函数体内部的变量都可以保存在函数作用域内--------------闭包
当调用函数时,闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链时,事情就变得很微妙;
当一个函数嵌套了另一个函数时,外部函数将嵌套的函数对象作为返回值的时候往往会发生这样的事情;
1、了解闭包首先要了解嵌套函数的词法作用域规则
闭包特性 可以捕捉到局部变量(和参数)并一直保存下来,看起来像变量绑定到了在其中定义它们的外部函数。
2、实现闭包:
函数定义时的作用域链到函数执行时以及函数执行结束后,仍然有效。
回想作用域链,每次调用js函数时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。
当函数返回的时候,就从域链中将这个绑定变量的对象删除。
如果不存在嵌套的函数,每个嵌套函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。
如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当作垃圾回收。
如果这个函数定义了嵌套函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一外部引用指向这个嵌套的函数,他就不会作为垃圾被回收,
并且它所指向的变量绑定对象也不会被当做垃圾回收
闭包可以捕捉单个函数调用时的局部变量,并将这些变量用作私有状态。
自定义函数:
uniqueInterget.counter=0;
function uniqueInterget(){ return uniqueInterget.counter++ ;}
此时,恶意代码可能将计数器重置或者把一个非正数的值赋个它,导致函数不一定能产生”唯一的“整数;
闭包重写:
var uniqueInterget=(function(){
var counter=0;
return function(){return counter++;};
}());
第一段代码定义了一个立即调用的函数(函数的开始带有左圆括号),因此是这个函数的返回值赋给变量uniqueInterget。
函数体中,这个函数返回另一个函数,这是一个嵌套函数,我们将它赋值给变量uniqueInterget,嵌套的函数是可以访问作用域内的变量的,而且可以访问外部函数中定义的counter变量
当外部函数返回之后,其他任何代码都无法访问counter变量,只有内部的函数才能访问到它。
对于counter私有变量,并不是只能在一个单独的闭包内,在同一个外部函数内定义的多个嵌套函数也可以访问它,且多个嵌套函数都共享一个作用域链:
function counter() {
var n=0;
return {
count:function () {
return n++;
},
reset:function () {
n = 0;
}
};
}
var c=counter(),d=counter(); //创建两个计数器
c.count(); //0
d.count(); //0 它们互不干扰
c.reset(); //reset() 和count()方法共享状态
c.count(); //0 因为重置了C
d.count(); //1 因为没有重置d 闭包技术可以用来共享的私有状态的通用做法。利用闭包实现私有属性存取器方法
在同一个作用域链中定义2个闭包,可以同时共享同样的私有变量或变量。
/*该函数返回一个总是返回v的函数*/
function constfun(v) {
return function () {
return v;
} ;
}
/*创建一个数组来存储常数函数*/
var funcs=[];
for (var i=0;i<10;i++){
funcs[i]=constfun(i);
}
/*在第五个位置上的元素表示函数的返回值为5*/
alert( funcs[5]()); /*5*/ 这段代码创建了很多闭包,当时常常会犯一个错误,那就是试图将循环代码移入定义这个闭包的函数之内。
function constfuncs() {
var funcs=[];
for (var i=0;i<10;i++){
funcs[i]=function () {
return i;
}; }
return funcs;
}
var funcs=constfuncs();
alert(funcs[5]());/*10*/
该段代码创建了10个闭包,并将它们存储到了一个数组中。这些闭包都是在同一个函数中调用中定义的,因此它们可以共享变量i。
当constfuncs()返回时,变量i的值是10,所以闭包都共享这一个值,因此数组的返回值都返回同一个值;
嵌套的函数不会将作用域内的私有成员复制一份,也不会对所绑定的变量生成静态快照。 书写闭包时,this是js关键字,而不是变量。如果闭包在外部函数里是无法访问this的,除非外部函数将this转存在一个变量。
var self=this;//将this保存在一个变量中,以便嵌套的函数能够访问它。 同样 arguments并不是一个关键字,但是在调用每个函数时都会自动声明它,由于闭包具有自己绑定的arguments,因此闭包内无法直接访问外部函数的参数数组。
除非外部函数将参数数组保存到另外一个变量中;var outerarguments=arguments;
js函数(4)闭包的更多相关文章
- js匿名自执行函数中闭包的高级使用(---------------------------******-----------------------------)
先看看最常见的一个问题: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- js匿名函数和闭包总结
js匿名函数和闭包总结 一.总结 一句话总结:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁.内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕.闭包可以用 ...
- 【学习笔记】深入理解js原型和闭包(2)——函数和对象的关系
上文(深入理解jS原型和闭包(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; console.log ...
- js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)
js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...
- js函数只执行一次,函数重写,变量控制与闭包三种做法
一.情景需求 调用后台接口需要附带token信息,那么在每个请求的头部添加token的做法就不太优雅了:一个网站请求100次,那就得写添加100次token,假设某天接口有所变动,改起来就十分麻烦了. ...
- 《JS语言精粹》学习笔记 函数部分の闭包
要理解闭包,首先要理解变量作用域,变量的作用域就两种,全局变量和局部变量,函数内部可以直接读取全局变量,函数外部无法读取函数内部的局部变量. 闭包定义:能读取函数内部局部变量的函数就是闭包,而只有函数 ...
- js 函数闭包内部返回函数体调用方法难点解答
今天在网上,看到一篇关于js函数难点的文章,js函数的一些难点.在那上面提了一下,关于js函数返回另一个函数的问题,并附上了一道面试题: var add = function(x){ var sum ...
- Js函数function基础理解
正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...
- JS 函数的柯里化与反柯里化
===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...
随机推荐
- java线程安全与不安全的理解
存在成员变量(全局变量)的类用于多线程时是不安全的,不安全体现在这个成员变量可能发生非原子性的操作,而变量定义在方法内也就是局部变量是线程安全的. 想想在使用struts1时,不推荐创建成员变量,因为 ...
- Codevs 1768 种树 3(差分约束)
1768 种树 3 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 为了绿化乡村,H村积极响应号召,开始种树了. H村里有n幢 ...
- 在windows10 Linux (centos7)中安装go golang (够浪) 并测试运行
官方下载安装页面 https://golang.org/doc/install git主页 https://github.com/golang/go 相关下载地址 https://golang.org ...
- Kafka详细原理
Kafka Kafka是最初由Linkedin公司开发,是一个分布式.支持分区的(partition).多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实 ...
- QtCreator集成的MSVC套件有问题
MSVC编译出来的内部签名算法的程序,相同的代码,验签结果和MINGW编译出来的不一样.MINGW编译出来的结果是正确的 怀疑是因为QtCreator集成的msvc有问题,可能是编码问题,可能是其他问 ...
- 浏览器环境下的microtaks和macrotasks
带有可视代码执行顺序的原文链接https://jakearchibald.com/201...,此篇文字并非其完整翻译,加入了一部分自己的理解,比如将其中的task替换为macrotask或是删除了可 ...
- [SpringBoot/SpringMVC]从Webapp下载一个大文件出现java.lang.OutOfMemoryError: GC overhead limit exceeded怎么办?
本文示例工程下载:https://files.cnblogs.com/files/xiandedanteng/WebFileDownload20191026.rar 制作一个Webapp,让其中一个网 ...
- LocalDB数据库修改排序规则,修复汉字变问号
VS中新增的轻量级数据库LocalDB,有个这个,开发人员就不必再安装庞大的SQL server了,可以方便地测试运行小型项目:既然是轻量级数据库,它抛弃了庞大的身躯,功能上当然也会受到局限,其中之一 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_6.RabbitMQ研究-入门程序-消费者
我们在consumer这个功能下进行代码的编写 首先是新建这个层级的包 创建入门程序的消费者 消费者也需要和mq建立通道.建立连接创建通道 在顶部都声明这个队列 下面写核心代码监听队列.basicCo ...
- python3 super().__init__() 和 __init__() 的区别
1.单继承 super().__int__()和 Base.__init__(self)是一样的, super()避免了基类的显式调用. class Base(object): def __init_ ...