javascript笔记整理系列
来源:互联网 发布:js删除注释工具 编辑:程序博客网 时间:2024/06/17 20:30
1 什么是闭包
1.1 作用域链
- 函数的执行依赖于变量作用域,这个作用域是在创建函数定义是决定的,而不是在调用时决定的。
要理解闭包,就必须先了解作用域链。看代码
function f1() { var n = 999; function f2() { var m = 1; alert(n); //999 } alert(m); //error:无法访问变量m。}
从上面代码我们可以看出,f2可以访问f1内局部变量,但反过来不行。
1.2 从外部获取函数局部变量
还是上面的函数,如果我们希望从外部获取f1函数的变量n,就像在f1中获取f2的局部变量m一样不可行。但是f2何以获取n,我们利用这一点来获取变量n。
function f1() { var n = 999; function f2() { console.log(n); } return f2;}f1()(); //999
1.3 闭包的概念
闭包概念:
闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
其他理解:
通过1.2我们了解如何从函数外访问函数内的变量,例子中的f2就是闭包。闭包连接了函数外与函数的作用域。所以在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。有权访问另一个函数作用域内变量的函数都是闭包
个人理解:
我们也可以通过”闭包”这两个字面来理解。拿上面的代码来说,有人会提出质疑:既然在javascript中函数也是对象,那执行f1()返回的f2函数也只是简单的将f2函数当作对象返回。这种质疑没错,f1函数中确实将f2函数当作对象返回,但重要的时,f1的return同时将内部作用域也一起返回出来,而并不是仅仅返回f2对象。如此说来,”包”这个字就好理解了:将作用域及f2”打包”返回。而”闭”则代表封闭的意思,也就是f1函数的作用域封闭。
2 闭包的作用
总结起来,闭包有俩作用:
1. 可在外部读取函数内部的变量。
2. 让闭包所占用的资源始终保存在内存中,不会被垃圾回收机制GC回收。。
function f1() { var n = 999; nAdd = function () { n += 1 } function f2() { alert(n); } return f2; } var result = f1(); result(); // 999 nAdd(); result(); // 1000
3 Javascript的垃圾回收机制
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
4 详解闭包
function a() { var i = 0; function b() { alert(++i); } return b;}var c = a();c();
如果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:
函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。
- 当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。
- 当执行函数a的时候,a会进入相应的执行环境(excution context)。
- 在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。
- 然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。
- 下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。
- 最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。
到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。
5 闭包的应用场景
- 保护函数内的变量安全。
- 在内存中维持一个变量。
- 通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)。
var counter = function () { var n = 0; return { count: function () { return n++; }, reset: function () { n = 0; } }}var c = counter(), d = counter();c.count(); //0d.count(); //0c.reset();c.count(); //1d.count(); //0
每次调用counter()都会创建一个新的作用域链和一个新的私有变量,所以c和d的私有变量互不干扰。
6 通过闭包实现getter和setter
function counter(n){ return { get count() { return n++; }, set count(m){ n = m; } };}var a = counter(100);console.log(a.count); //100a.count = 200;console.log(a.count); //200
- get set关键字为ES5添加,支持IE9+。
7 闭包出现的问题
- 由于闭包将变量式中保存在内存中,可能会导致内存溢出。
- 闭包可以访问函数内的局部变量,所以可能会错误的修改局部变量。
- 不希望共享的变量共享了其他的闭包:
function constfuncs(){ var funcs = []; for(var i=0; i<10; i++){ funcs[i] = function(){ return i; }; } return funcs;}var funcs = constfuncs();funcs[5](); //结果是?
上面函数利用for循环创建了多个闭包,但这些闭包内返回的是constcuncs函数内的局部变量i。其实只有一个变量i,每一个闭包返回的都是这个变量i。最后i为10跳出循环,所以funcs5的结果是10。
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理系列
- javascript笔记整理
- JavaScript学习笔记整理
- 初学JavaScript,整理整理笔记(一)
- 初学javascript,整理整理笔记(二)
- 多年JavaScript学习笔记整理
- 【阿里聚安全技术公开课】业务安全及防护(数据风控)
- Unity3D 篮球游戏 上线项目源码
- Java Date与String的相互转换
- 数据库分表之merge引擎
- cd ~/.config
- javascript笔记整理系列
- Redis主要功能
- Jackson属性的过滤
- ubuntu 16.04 安装TensorFlow GPU版本
- 极光消息推送(配置与初始化)
- Json 在 Android中的应用
- JS获取地址栏参数(解决参数中文乱码的问题)
- tensorflow学习笔记十四:TF官方教程学习 tf.contrib.learn Quickstart
- redis的存储结构