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 相关文章推荐
一个对于Array的简单扩展
Oct 03 Javascript
把textarea中字符串里含有的回车换行替换成&amp;lt;br&amp;gt;的javascript代码
Apr 20 Javascript
javascript 函数式编程
Aug 16 Javascript
javascript getElementsByClassName实现代码
Oct 11 Javascript
Jquery 实现表格颜色交替变化鼠标移过颜色变化实例
Aug 28 Javascript
js 判断文件类型并控制表单提交示例代码
Nov 14 Javascript
Javascript实现鼠标右键特色菜单
Aug 04 Javascript
JavaScript函数的调用以及参数传递
Oct 21 Javascript
jquery siblings获取同辈元素用法实例分析
Jul 25 Javascript
纯JavaScript实现实时反馈系统时间
Oct 26 Javascript
详解vue中router-link标签所必备了解的属性
Apr 15 Javascript
JS遍历树层级关系实现原理解析
Aug 31 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
《PHP编程最快明白》第三讲:php数组
2010/11/01 PHP
php 数组的一个悲剧?
2011/05/11 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
2016/09/09 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
PHP时间函数使用详解
2019/03/21 PHP
JQuery Ajax 跨域访问的解决方案
2010/03/12 Javascript
Javascript 面试题随笔
2011/03/31 Javascript
NodeJS框架Express的模板视图机制分析
2011/07/19 NodeJs
用jquery实现点击栏目背景色改变
2012/12/10 Javascript
基于jQuery.Validate验证库知识点的详解
2013/04/26 Javascript
js一般方法改写成面向对象方法的无限级折叠菜单示例代码
2013/07/04 Javascript
使用JS 清空File控件的路径值
2013/07/08 Javascript
Function.prototype.bind用法示例
2013/09/16 Javascript
javascript中数组的concat()方法使用介绍
2013/12/18 Javascript
JS、DOM和JQuery之间的关系示例分析
2014/04/09 Javascript
jquery中 $.expr使用实例介绍
2014/06/09 Javascript
jQuery文件上传控件 Uploadify 详解
2016/06/20 Javascript
AngularJS实现Input格式化的方法
2016/11/07 Javascript
浅谈angular.copy() 深拷贝
2017/09/14 Javascript
vue中使用localstorage来存储页面信息
2017/11/04 Javascript
vue的滚动条插件实现代码
2019/09/07 Javascript
jQuery 选择器用法基础入门示例
2020/01/04 jQuery
js实现的订阅发布者模式简单示例
2020/03/14 Javascript
Python实现的简单算术游戏实例
2015/05/26 Python
Python字符串格式化输出方法分析
2016/04/13 Python
Python正则替换字符串函数re.sub用法示例
2017/01/19 Python
Python中input与raw_input 之间的比较
2017/08/20 Python
django处理select下拉表单实例(从model到前端到post到form)
2020/03/13 Python
pandas 强制类型转换 df.astype实例
2020/04/09 Python
python脚本第一行如何写
2020/08/30 Python
编写strcpy函数
2014/06/24 面试题
实验教师岗位职责
2014/02/13 职场文书
泰山导游词
2015/02/02 职场文书
硕士论文致谢范文
2015/05/14 职场文书
2016年党风廉政建设承诺书
2016/03/25 职场文书
mybatis 获取无数据的字段不显示的问题
2021/07/15 Java/Android