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 相关文章推荐
js获取TreeView控件选中节点的Text和Value值的方法
Nov 24 Javascript
JS下拉缓冲菜单示例代码
Aug 30 Javascript
使用jQuery实现更改默认alert框体
Apr 13 Javascript
JS利用cookie记忆当前位置的防刷新导航效果
Oct 15 Javascript
jquery实现横向图片轮播特效代码分享
Nov 19 Javascript
Vue响应式原理详解
Apr 18 Javascript
微信小程序实现YDUI的ScrollTab组件
Feb 02 Javascript
React组件中的this的具体使用
Feb 28 Javascript
create-react-app构建项目慢的解决方法
Mar 14 Javascript
node.js读取Excel数据(下载图片)的方法示例
Aug 02 Javascript
node实现分片下载的示例代码
Oct 17 Javascript
uniapp实现横向滚动选择日期
Oct 21 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
让Json更懂中文(JSON_UNESCAPED_UNICODE)
2011/10/27 PHP
laravel 4安装及入门图文教程
2014/10/29 PHP
WordPress中&quot;无法将上传的文件移动至&quot;错误的解决方法
2015/07/01 PHP
IE6与IE7中,innerHTML获取param的区别
2009/03/15 Javascript
JavaScript中的闭包原理分析
2010/03/08 Javascript
JQuery实现的在新窗口打开链接的方法小结
2010/04/22 Javascript
javascript 弹出窗口中是否显示地址栏的实现代码
2011/04/14 Javascript
js中scrollHeight,scrollWidth,scrollLeft,scrolltop等差别介绍
2012/05/16 Javascript
jQuery 获取和设置select下拉框的值实现代码
2013/11/08 Javascript
wangEditor编辑器失去焦点后仍然可以在原位置插入图片分析
2015/05/06 Javascript
JavaScript数组对象赋值用法实例
2015/08/04 Javascript
window.onload使用指南
2015/09/13 Javascript
Servlet实现文件上传,可多文件上传示例
2016/12/05 Javascript
Js中将Long转换成日期格式的实现方法
2018/06/05 Javascript
Vue实现按钮旋转和移动位置的实例代码
2018/08/09 Javascript
浅谈微信JS-SDK 微信分享接口开发(介绍版)
2018/08/15 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
2018/09/21 Javascript
Angular4 Select选择改变事件的方法
2018/10/09 Javascript
javascript实现计算器功能
2020/03/30 Javascript
vue.js实现双击放大预览功能
2020/06/23 Javascript
[42:04]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第一局
2016/03/03 DOTA
[07:54]DOTA2-DPC中国联赛 正赛 iG vs VG 选手采访
2021/03/11 DOTA
Python二分法搜索算法实例分析
2015/05/11 Python
python使用Flask操作mysql实现登录功能
2018/05/14 Python
django项目登录中使用图片验证码的实现方法
2019/08/15 Python
Django中的FBV和CBV用法详解
2019/09/15 Python
wxPython实现整点报时
2019/11/18 Python
python 计算概率密度、累计分布、逆函数的例子
2020/02/25 Python
Jupyter notebook 启动闪退问题的解决
2020/04/13 Python
Desigual英国官网:在线购买原创服装
2018/03/09 全球购物
Etam艾格英国官网:法国著名女装品牌
2019/04/15 全球购物
音乐器材管理制度
2014/01/31 职场文书
大学三年计划书范文
2014/04/30 职场文书
学生会竞选演讲稿学习部
2014/08/25 职场文书
高校自主招生自荐信2015
2015/03/04 职场文书
Mysql数据库事务的脏读幻读及不可重复读详解
2022/05/30 MySQL