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)闭包的更多相关文章

  1. js匿名自执行函数中闭包的高级使用(---------------------------******-----------------------------)

    先看看最常见的一个问题: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  2. js匿名函数和闭包总结

    js匿名函数和闭包总结 一.总结 一句话总结:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁.内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕.闭包可以用 ...

  3. 【学习笔记】深入理解js原型和闭包(2)——函数和对象的关系

    上文(深入理解jS原型和闭包(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; console.log ...

  4. js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)

    js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...

  5. js函数只执行一次,函数重写,变量控制与闭包三种做法

    一.情景需求 调用后台接口需要附带token信息,那么在每个请求的头部添加token的做法就不太优雅了:一个网站请求100次,那就得写添加100次token,假设某天接口有所变动,改起来就十分麻烦了. ...

  6. 《JS语言精粹》学习笔记 函数部分の闭包

    要理解闭包,首先要理解变量作用域,变量的作用域就两种,全局变量和局部变量,函数内部可以直接读取全局变量,函数外部无法读取函数内部的局部变量. 闭包定义:能读取函数内部局部变量的函数就是闭包,而只有函数 ...

  7. js 函数闭包内部返回函数体调用方法难点解答

    今天在网上,看到一篇关于js函数难点的文章,js函数的一些难点.在那上面提了一下,关于js函数返回另一个函数的问题,并附上了一道面试题: var add = function(x){ var sum ...

  8. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  9. JS 函数的柯里化与反柯里化

    ===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...

随机推荐

  1. box-orient

    box-orient 语法: box-orient:horizontal | vertical | inline-axis | block-axis 默认值:horizontal 适用于:伸缩盒容器大 ...

  2. ckeditor粘贴word文档图片的思路

    由于工作需要必须将word文档内容粘贴到编辑器中使用 但发现word中的图片粘贴后变成了file:///xxxx.jpg这种内容,如果上传到服务器后其他人也访问不了,网上找了很多编辑器发现没有一个能直 ...

  3. python-selenium视频教程分享

    1.python电子书 2.课件 3.前段调试工具 4.文档资料 5.python-selenium课程列表 6.sele01-sele22 百度网盘连接:链接: https://pan.baidu. ...

  4. C语言学习笔记7-字符串

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/50752405 作者:jadeshu   邮箱: jades ...

  5. C# 窗体 类似framest 左侧点击右侧显示 左侧菜单右侧显示

    首先托一个splitContainer调节大小位置 然后进行再新创建一个窗体名为add 在左侧拖入button按钮 进入代码阶段 更改属性 public Main() { InitializeComp ...

  6. http代理和SOCKS代理的区别

    HTTP 代理按匿名功能分类(是否具有隐藏 IP 的功能) 非匿名代理:不具有匿名功能. 匿名代理.使用此种代理时,虽然被访问的网站不能知道你的 IP 地址,但仍然可 以知道你在使用代理,有些侦测 I ...

  7. Java-ZipUtil

    Zip 压缩工具类,不支持压缩空文件夹. 简单版 import java.io.FileOutputStream; import java.io.IOException; import java.ni ...

  8. [go]日志库小例子

    输出日志 //输出日志到console msg := fmt.Sprintf(format, args...) //format里的坑 args解出的数据相匹配 fmt.Fprintf(os.Stdo ...

  9. leetcode 96. Unique Binary Search Trees 、95. Unique Binary Search Trees II 、241. Different Ways to Add Parentheses

    96. Unique Binary Search Trees https://www.cnblogs.com/grandyang/p/4299608.html 3由dp[1]*dp[1].dp[0]* ...

  10. Editplus的运行JAVA的配置

    工具--->参数设置