轻松学习Javascript闭包


Posted in Javascript onMarch 01, 2017

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

当function里嵌套function时,内部的function可以访问外部function里的变量。

function foo(x) {
 var tmp = 3;
 function bar(y) {
  alert(x + y + (++tmp));
 }
 bar(10);
}
foo(2)

不管执行多少次,都会alert 16,因为bar能访问foo的参数x,也能访问foo的变量tmp。

但,这还不是闭包。当你return的是内部function时,就是一个闭包。内部function会close-over外部function的变量直到内部function结束。

function foo(x) {
 var tmp = 3;
 return function (y) {
  alert(x + y + (++tmp));
 }
}
var bar = foo(2); // bar 现在是一个闭包
bar(10);

上面的脚本最终也会alert 16,因为虽然bar不直接处于foo的内部作用域,但bar还是能访问x和tmp。

但是,由于tmp仍存在于bar闭包的内部,所以它还是会自加1,而且你每次调用bar时它都会自加1.

(考虑到六岁这个限制:我们其实可以建立不止一个闭包方法,比如return它们的数组,也可以把它们设置为全局变量。它们全都指向相同的x和相同的tmp,而不是各自有一份副本。)

注:现在来整点儿七岁的内容。

上面的x是一个字面值(值传递),和JS里其他的字面值一样,当调用foo时,实参x的值被复制了一份,复制的那一份作为了foo的参数x。

那么问题来了,JS里处理object时是用到引用传递的,那么,你调用foo时传递一个object,foo函数return的闭包也会引用最初那个object!

function foo(x) {
var tmp = 3;
return function (y) {
 alert(x + y + tmp);
 x.memb = x.memb ? x.memb + 1 : 1;
 alert(x.memb);
 }
}
var age = new Number(2);
var bar = foo(age); // bar 现在是一个引用了age的闭包
bar(10);

不出我们意料,每次运行bar(10),x.memb都会自加1。但需要注意的是x每次都指向同一个object变量——age,运行两次bar(10)后,age.memb会变成2.

这和HTML对象的内存泄漏有关,呃,不过貌似超出了答题的范围。

这里有一个不用return关键字的闭包例子:

function closureExample(objID, text, timedelay) { 
  setTimeout(function() { 
    document.getElementById(objID).innerHTML = text; 
  }, timedelay); 
} 
closureExample(‘myDiv', ‘Closure is created', 500); 

JS里的function能访问它们的:

1. 参数

2. 局部变量或函数

3. 外部变量(环境变量?),包括

3.1 全局变量,包括DOM。

3.2 外部函数的变量或函数。

如果一个函数访问了它的外部变量,那么它就是一个闭包。

注意,外部函数不是必需的。通过访问外部变量,一个闭包可以维持(keep alive)这些变量。在内部函数和外部函数的例子中,外部函数可以创建局部变量,并且最终退出;但是,如果任何一个或多个内部函数在它退出后却没有退出,那么内部函数就维持了外部函数的局部数据。

一个典型的例子就是全局变量的使用。

闭包经常用于创建含有隐藏数据的函数(但并不总是这样)。

var db = (function() {
// 创建一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 创建一个函数, 这个函数提供一些访问data的数据的方法
return function(key, val) {
  if (val === undefined) { return data[key] } // get
  else { return data[key] = val } // set
  }
// 我们可以调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})();
db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员

下面看下使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

以上所述是小编给大家介绍的Javascript闭包知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript 处理HTML元素必须避免使用的一种方法
Jul 30 Javascript
用js设置下拉框为只读的小技巧
Apr 10 Javascript
JQuery实现的购物车功能(可以减少或者添加商品并自动计算价格)
Jan 13 Javascript
JS+DIV实现鼠标划过切换层效果的方法
May 25 Javascript
jquery form表单获取内容以及绑定数据
Feb 24 Javascript
jQuery通过写入cookie实现更换网页背景的方法
Apr 15 Javascript
JavaScript判断页面加载完之后再执行预定函数的技巧
May 17 Javascript
jQuery图片渐变特效的简单实现
Jun 25 Javascript
根据输入邮箱号跳转到相应登录地址的解决方法
Dec 13 Javascript
vue2 中如何实现动态表单增删改查实例
Jun 09 Javascript
jQuery实现每隔一段时间自动更换样式的方法分析
May 03 jQuery
浅谈js数组splice删除某个元素爬坑
Oct 14 Javascript
js图片延迟加载(Lazyload)三种实现方式
Mar 01 #Javascript
node.js实现回调的方法示例
Mar 01 #Javascript
JQ中$(window).load和$(document).ready区别与执行顺序
Mar 01 #Javascript
Angular2库初探
Mar 01 #Javascript
浅谈angular2的http请求返回结果的subcribe注意事项
Mar 01 #Javascript
JavaScript两个变量交换值的实现方法
Mar 01 #Javascript
js实现仿购物车加减效果
Mar 01 #Javascript
You might like
php环境配置 php5 MySQL5 apache2 phpmyadmin安装与配置图文教程
2007/03/16 PHP
学习discuz php 引入文件的方法DISCUZ_ROOT
2009/06/21 PHP
php中使用sftp教程
2015/03/30 PHP
php获取错误信息的方法
2015/07/17 PHP
PHP+redis实现微博的推模型案例分析
2019/07/10 PHP
实例讲解PHP表单
2020/06/10 PHP
dojo 之基础篇(三)之向服务器发送数据
2007/03/24 Javascript
jQuery 技巧小结
2010/04/02 Javascript
jquery attr 设定src中含有&(宏)符号问题的解决方法
2011/07/26 Javascript
jquery滚动组件(vticker.js)实现页面动态数据的滚动效果
2013/07/03 Javascript
JavaScript三元运算符的多种使用技巧
2015/04/16 Javascript
JavaScript中的Math.LOG2E属性使用详解
2015/06/14 Javascript
JS IOS/iPhone的Safari浏览器不兼容Javascript中的Date()问题如何解决
2016/11/11 Javascript
vue如何引入sass全局变量
2018/06/28 Javascript
angularjs 的数据绑定实现原理
2018/07/02 Javascript
Vue在页面数据渲染完成之后的调用方法
2018/09/11 Javascript
vue权限管理系统的实现代码
2019/01/17 Javascript
在Chrome DevTools中调试JavaScript的实现
2020/04/07 Javascript
element跨分页操作选择详解
2020/06/29 Javascript
vue3.0中使用element的完整步骤
2021/03/04 Vue.js
[03:01]2014DOTA2国际邀请赛 小组赛7月13日TOPPLAY
2014/07/14 DOTA
Python二叉搜索树与双向链表转换实现方法
2016/04/29 Python
浅谈python numpy中nonzero()的用法
2018/04/02 Python
Python3环境安装Scrapy爬虫框架过程及常见错误
2019/07/12 Python
python实现字符串完美拆分split()的方法
2019/07/16 Python
详细整理python 字符串(str)与列表(list)以及数组(array)之间的转换方法
2019/08/30 Python
如何将你的应用迁移到Python3的三个步骤
2019/12/22 Python
HTML5手机端弹出遮罩菜单特效代码
2016/01/27 HTML / CSS
用canvas画心电图的示例代码
2018/09/10 HTML / CSS
汽车电子与维修专业大学生求职信
2013/09/28 职场文书
医学检验专业大学生求职信
2013/11/18 职场文书
环保小标语
2014/06/13 职场文书
文员试用期转正自我鉴定
2014/09/14 职场文书
小学班级标语口号大全
2015/12/26 职场文书
面试分析分布式架构Redis热点key大Value解决方案
2022/03/13 Redis
Python探索生命起源 matplotlib细胞自动机动画演示
2022/04/21 Python