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 相关文章推荐
onpropertypchange
Jul 01 Javascript
Javascript实例教程(19) 使用HoTMetal(3)
Dec 23 Javascript
ext combobox动态加载数据库数据(附前后台)
Jun 17 Javascript
javascript跨域原因以及解决方案分享
Apr 08 Javascript
深入探讨javascript函数式编程
Oct 11 Javascript
JQuery实现的按钮倒计时效果
Dec 23 Javascript
Actionscript与javascript交互实例程序(修改)
Sep 22 Javascript
浅谈jquery选择器 :first与:first-child的区别
Nov 20 Javascript
bootstrap表格分页实例讲解
Dec 30 Javascript
React Native使用Modal自定义分享界面的示例代码
Oct 31 Javascript
微信小程序实现的自定义分享功能示例
Feb 12 Javascript
vue 百度地图(vue-baidu-map)绘制方向箭头折线实例代码详解
Apr 28 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
smarty简单分页的实现方法
2014/10/27 PHP
thinkphp3.2.2实现生成多张缩略图的方法
2014/12/19 PHP
Laravel中Facade的加载过程与原理详解
2017/09/22 PHP
JavaScript 基础知识 被自己遗忘的
2009/10/15 Javascript
js中字符替换函数String.replace()使用技巧
2011/08/14 Javascript
浅谈Javascript如何实现匀速运动
2014/12/19 Javascript
php+ajax+jquery实现点击加载更多内容
2015/05/03 Javascript
JavaScript实现鼠标滑过处生成气泡的方法
2015/05/16 Javascript
跟我学习javascript的基本类型和引用类型
2015/11/16 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
2016/02/14 Javascript
Angularjs中controller的三种写法分享
2016/09/21 Javascript
微信小程序 网络API Websocket详解
2016/11/09 Javascript
js仿淘宝商品放大预览功能
2017/03/15 Javascript
vue中如何引入jQuery和Bootstrap
2017/04/10 jQuery
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
如何重置vue打印变量的显示方式
2017/12/06 Javascript
nodejs前端模板引擎swig入门详解
2018/05/15 NodeJs
vue后台管理之动态加载路由的方法
2018/08/13 Javascript
angularJs中跳转到指定的锚点实例($anchorScroll)
2018/08/31 Javascript
js实现小星星游戏
2020/03/23 Javascript
vue.js 解决v-model让select默认选中不生效的问题
2020/07/28 Javascript
用Python编写一个基于终端的实现翻译的脚本
2015/04/24 Python
python通过索引遍历列表的方法
2015/05/04 Python
12步入门Python中的decorator装饰器使用方法
2016/06/20 Python
浅析python协程相关概念
2018/01/20 Python
linux安装python修改默认python版本方法
2019/03/31 Python
Python 爬取必应壁纸的实例讲解
2020/02/24 Python
Python 存取npy格式数据实例
2020/07/01 Python
python3.7调试的实例方法
2020/07/21 Python
HTML5实现经典坦克大战坦克乱走还能发出一个子弹
2013/09/02 HTML / CSS
英国珠宝网站Argento: PANDORA、Olivia Burton和Nomination等
2020/05/08 全球购物
大学生职业生涯规划范文——找准自我,定位人生
2014/01/23 职场文书
思想作风纪律整顿心得体会
2014/09/04 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书
python 网络编程要点总结
2021/06/18 Python
不同品牌、不同型号对讲机如何互相通联
2022/02/18 无线电