Javascript学习笔记之 函数篇(三) : 闭包和引用


Posted in Javascript onNovember 23, 2014

Javascript 中一个最重要的特性就是闭包的使用。因为闭包的使用,当前作用域总可以访问外部的作用域。因为 Javascript 没有块级作用域,只有函数作用域,所以闭包的使用与函数是紧密相关的。

模拟私有变量

function Counter(start) {

    var count = start;

    return {

        increment: function() {

            count++;

        },

        get: function() {

            return count;

        }

    }

}

var foo = Counter(4);

foo.increment();

foo.get(); // 5

这里 Counter 返回两个闭包:函数 increment 和 get。这两个函数一直保持着对 Counter 作用域的访问,因此它们能一直访问到定义在 Counter 作用域的变量 count。

私有变量的工作机制

由于 Javascript 不可以对作用域赋值和引用,所以在上例中,是没有办法在外部直接访问内部私有变量 count。唯一的方法就是通过定义闭包来访问。

var foo = new Counter(4);

foo.hack = function() {

    count = 1337;

};

上面的代码不会改变 Counter 作用域内的 count 变量值,因为 hack 没有在 Counter 内定义。上面这段代码只会创建或者覆盖全局变量 count。

循环内的闭包

一个最容易犯的错误就是在循环内使用闭包。

for(var i = 0; i < 10; i++) {

    setTimeout(function() {

        console.log(i);  

    }, 1000);

}

上面这段代码不会输出0到9,而是连续输出10次10。
上面的匿名会一直保持一个对变量 i 的引用。当调用 console.log 函数开始输出时,这是循环已经结束,而变量 i 已经为10了。
为了避免上面的错误发生,我们需要在每次循环时为变量 i 值创建一个拷贝。

避免引用错误

为了复制循环中变量的值,最好的方式是在外层加一个匿名的立刻执行函数。

for(var i = 0; i < 10; i++) {

    (function(e) {

        setTimeout(function() {

            console.log(e);  

        }, 1000);

    })(i);

}

这个外部的匿名函数接收循环变量 i 作为第一个参数,并将其值拷贝至它自身的参数 e。
外部的匿名函数将参数 e 再传递给 setTimeout,因此 setTimeout 有了指向参数 e 的引用。而且这个参数 e 的值不会因为外部的循环改变而改变。

还有另外一个方法可以实现同样的效果,就是在 setTimeout 内的匿名函数中再返回一个匿名函数:

for(var i = 0; i < 10; i++) {

    setTimeout((function(e) {

        return function() {

            console.log(e);

        }

    })(i), 1000)

}

此外,通过 bind 方法也可以实现。

for(var i = 0; i < 10; i++) {

    setTimeout(console.log.bind(console, i), 1000);

}

文章最后我们来总结下:

(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;
(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;
(3)尽量少学习。

Javascript 相关文章推荐
getElementsByTagName vs selectNodes效率 及兼容的selectNodes实现
Feb 26 Javascript
javascript 跨浏览器开发经验总结(五) js 事件
May 19 Javascript
兼容ie、firefox的图片自动缩放的css跟js代码分享
Jan 21 Javascript
js检测用户输入密码强度
Oct 22 Javascript
jQuery布局组件EasyUI Layout使用方法详解
Feb 28 Javascript
前端把html表格生成为excel表格的实例
Sep 19 Javascript
jQuery插件Validation表单验证详解
May 26 jQuery
基于Vue 服务端Cookies删除的问题
Sep 21 Javascript
说说如何利用 Node.js 代理解决跨域问题
Apr 22 Javascript
Javascript实现秒表计时游戏
May 27 Javascript
Vue的v-model的几种修饰符.lazy,.number和.trim的用法说明
Aug 05 Javascript
react使用antd的上传组件实现文件表单一起提交功能(完整代码)
Jun 29 Javascript
js实例属性和原型属性示例详解
Nov 23 #Javascript
JS常用函数使用指南
Nov 23 #Javascript
浅谈JSON和JSONP区别及jQuery的ajax jsonp的使用
Nov 23 #Javascript
理解jQuery stop()方法
Nov 21 #Javascript
JS中三目运算符和if else的区别分析与示例
Nov 21 #Javascript
node.js使用npm 安装插件时提示install Error: ENOENT报错的解决方法
Nov 20 #Javascript
JS在可编辑的div中的光标位置插入内容的方法
Nov 20 #Javascript
You might like
Laravel框架中扩展函数、扩展自定义类的方法
2014/09/04 PHP
php如何实现只替换一次或N次
2015/10/29 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
2007/05/07 Javascript
javascript 禁止复制网页
2009/06/11 Javascript
jQuery实现切换页面布局使用介绍
2011/10/09 Javascript
解决css和js的{}与smarty定界符冲突问题的两种方法
2013/09/10 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
2015/10/23 Javascript
JavaScript重载函数实例剖析
2016/05/13 Javascript
jQuery禁用快捷键例如禁用F5刷新 禁用右键菜单等的简单实现
2016/08/31 Javascript
js获取当前时间(昨天、今天、明天)
2016/11/23 Javascript
jQuery实现发送验证码并60秒倒计时功能
2016/11/25 Javascript
addEventListener()与removeEventListener()解析
2017/04/20 Javascript
Node.js中的cluster模块深入解读
2018/06/11 Javascript
微信小程序使用蓝牙小插件
2019/09/23 Javascript
Python2.7基于淘宝接口获取IP地址所在地理位置的方法【测试可用】
2017/06/07 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python编程pygal绘图实例之XY线
2017/12/09 Python
python3.x+pyqt5实现主窗口状态栏里(嵌入)显示进度条功能
2019/07/04 Python
基于python的列表list和集合set操作
2019/11/24 Python
使用Python串口实时显示数据并绘图的例子
2019/12/26 Python
根据tensor的名字获取变量的值方式
2020/01/04 Python
Python基于codecs模块实现文件读写案例解析
2020/05/11 Python
Python字符串函数strip()原理及用法详解
2020/07/23 Python
一篇文章带你搞定Ubuntu中打开Pycharm总是卡顿崩溃
2020/11/02 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
2021/03/01 Python
高档奢华时装在线目的地:FORWARD by elyse walker
2017/10/16 全球购物
Maison Lab荷兰:名牌Outlet购物
2018/08/10 全球购物
德国专业木制品经销商:Holz-Direkt24
2019/12/26 全球购物
Jowissa官方网站:瑞士制造的手表,优雅简约的设计
2020/07/29 全球购物
什么是静态路由,其特点是什么?什么是动态路由,其特点是什么?
2013/07/26 面试题
儿子婚宴答谢词
2014/01/09 职场文书
应届生简历中的自我评价
2014/01/13 职场文书
开会迟到检讨书范文
2015/05/06 职场文书
学校2016年全国助残日活动总结
2016/04/01 职场文书
《进击的巨人》新联动CM 兵长强势出击兽巨人
2022/04/05 日漫