轻松学习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 相关文章推荐
jsPDF生成pdf后在网页展示实例
Jan 16 Javascript
AngularJS 所有版本下载地址
Sep 14 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
Mar 08 Javascript
Mongoose经常返回e11000 error的原因分析
Mar 29 Javascript
ES6新特性三: Generator(生成器)函数详解
Apr 21 Javascript
vue 实现在函数中触发路由跳转的示例
Sep 01 Javascript
详解Webstorm 下的Angular2.0开发之路(图文)
Dec 06 Javascript
vue+element实现打印页面功能
May 20 Javascript
实现高性能javascript的注意事项
May 27 Javascript
vue-cli点击实现全屏功能
Mar 07 Javascript
vue实现循环滚动列表
Jun 30 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
Sep 16 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
使用bcompiler对PHP文件进行加密的代码
2010/08/29 PHP
php实现过滤表单提交中html标签的方法
2014/10/17 PHP
PHP也能干大事之PHP中的编码解码详解
2015/04/20 PHP
利用“多说”制作留言板、评论系统
2015/07/14 PHP
WordPress中限制非管理员用户在文章后只能评论一次
2015/12/31 PHP
Laravel jwt 多表(多用户端)验证隔离的实现
2019/12/18 PHP
PHP中->和=>的含义及使用示例解析
2020/08/06 PHP
使用JavaScript 实现各种跨域的方法
2013/05/08 Javascript
关于IE中getElementsByClassName不能用的问题解决方法
2013/08/26 Javascript
你可能不知道的JavaScript的new Function()方法
2014/04/17 Javascript
jQuery实现Email邮箱地址自动补全功能代码
2015/11/03 Javascript
jQuery插件开发精品教程(让你的jQuery更上一个台阶)
2015/11/07 Javascript
酷! 不同风格页面布局幻灯片特效js实现
2021/02/19 Javascript
AngularJS使用angular.bootstrap完成模块手动加载的方法分析
2017/01/19 Javascript
重新理解JavaScript的六种继承方式
2017/03/24 Javascript
js实现三级联动效果(简单易懂)
2017/03/27 Javascript
微信小程序在ios下Echarts图表不能滑动的问题解决
2019/07/10 Javascript
vant自定义二级菜单操作
2020/11/02 Javascript
Vant+postcss-pxtorem 实现浏览器适配功能
2021/02/05 Javascript
零基础写python爬虫之神器正则表达式
2014/11/06 Python
在Python中使用HTMLParser解析HTML的教程
2015/04/29 Python
详解如何为eclipse安装合适版本的python插件pydev
2018/11/04 Python
解决pandas .to_excel不覆盖已有sheet的问题
2018/12/10 Python
Python随机函数库random的使用方法详解
2019/08/21 Python
pygame实现贪吃蛇游戏(下)
2019/10/29 Python
如何基于Python获取图片的物理尺寸
2019/11/25 Python
Python爬虫之Selenium实现键盘事件
2020/12/04 Python
英国运动服、设备及配件网站:DW Sports
2019/12/04 全球购物
盛大二次面试题
2016/11/18 面试题
函授本科毕业自我鉴定
2013/10/09 职场文书
历史教育专业个人求职信
2013/12/13 职场文书
公司司机岗位职责
2014/02/07 职场文书
工作骂脏话检讨书
2014/10/05 职场文书
2014年幼儿园安全工作总结
2014/11/10 职场文书
2015年招聘工作总结
2014/12/12 职场文书
仅仅使用 HTML/CSS 实现各类进度条的方式汇总
2021/11/11 HTML / CSS