深入理解JavaScript——闭包
跟很多新手一样我也是初入前端,对闭包的理解花费的时间和精力相当的多。效果也还行,今天我就来根据自己的理解细致的讲一讲闭包,由于是初入学习的时候不免有一些弯路和困惑,我想信这也是很多跟我一样的人会同样遇到的问题。我就以自己的学习路径和遇到的各种坑来谈闭包。希望对各位有一定的帮助。(菜鸟,也请各位多多指教)
闭包是什么?《JavaScript高级程序设计》上面这么描述的:闭包是指有权访问另一个函数作用域中的变量的函数。这句话第一次看的时候模模糊糊,似是而非。碰到问题就不会运用了,听别人的分析头头是道,说到底还是没搞明白。现在我觉得要彻底搞清这句话必须对JavaScript的作用域,匿名函数,甚至JavaScript的编译原理有一些简单的了解。经过查阅理解各种资料书籍对闭包的解释,再回过头来看了一些源码,慢慢的有了一点感觉。我觉得对闭包描述最好的一句话是:“闭包是基于词法作用域书写代码时所产生的自然结果,你甚至不需要为了利用它而有意为之的创建闭包,闭包的创建和使用是在你的代码中随处可见。你缺少的是根据你自己的意愿来识别,拥抱和影响闭包的思维环境。”话有点长但点出来闭包在JavaScript这么语言中存在的实际价值,大家可以细细体会一下。接下来我已实际例子来讲讲闭包。
首先看一个简单的例子:
function createComparisonFunction(propertyName){
return function(obj1,obj2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
}
例子中返回的是一个匿名函数,其中匿名函数中value1,value2同时又对外部函数createComparisonFunction()的参数propertyName进行调用。再看看上面对闭包的定义:有权访问另一个函数作用域中的变量的函数。return的匿名函数有权访问外部函数作用域中的变量propertyName,因此这是一个闭包。但实际来说这只是一个基于词法作用域的查找规则,很好理解也很自然。
可能有些人不明白什么是词法作用域的查找规则:其实说简单点就是根据变量的作用链域来查找并取得该变量。以上例来说:createComparisonFunction函数的作用域包含一个变量property和一个匿名函数(由于没有函数名其实在createComparisonFunction函数中也无法调用,这也是匿名函数的一个缺点,记得事件监听函数调用一个匿名函数时是无法移除吗?道理是一样的),匿名函数作用域中包括obj1,obj2,value1,value2这四个变量。匿名函数中的变量调用时首先在自己作用域中查询,找到了该变量就调用,找不到就往外层走接着找,直到全局作用域如果还是找不到就会报ReferenceError(如果找到了一个var a;呢?由于a为undefined所以会报TypeError)。而createComparisonFunction函数则只能在他的作用域中查找,不能去内层的匿名函数中查找,这种查找规则就是词法作用域的查找规则(当然这不只是基本规则)。
我们再来看一个例子:
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); //2
答案可能很多人都能猜出来但其实现原理是怎样呢?我现在就来细致的分析一下:首先声明了一个函数foo其作用域包括变量a和bar函数。foo函数内部有一个函数bar内部没有新变量。然后定义一个变量baz,其值为foo()而foo()返回bar,顾baz=bar;最后一句baz()即等价于bar();根据词法作用域的规则bar是在foo函数中声明的。外部是无法访问的呀!这正是闭包的神奇之处!我们再一次回到闭包定义:有权访问另一个函数作用域中的变量的函数,baz()函数有权访问foo函数中的bar。这就是闭包对吧!搞清闭包后有些人还会疑问?闭包是怎么形成的,为什么你说它有权访问foo中的bar呢?首先闭包的形成是在一个函数内部创建一个函数这是创建闭包的最常见方法。当将内部函数传递到它的词法作用域以外他都会持有对原始定义作用域的引用,执行此函数就会 使用闭包。
闭包的基础大概就是这几点,希望大家能仔细体会。抽时间补充点闭包的一些其他用途,来帮大家扩展一下思维。
深入理解JavaScript——闭包的更多相关文章
- 我从来不理解JavaScript闭包,直到有人这样向我解释它...
摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...
- 深入理解JavaScript闭包【译】
在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ ...
- 【转】深入理解JavaScript闭包闭包(closure) (closure)
一.什么是闭包?"官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述 ...
- 全面理解Javascript闭包和闭包的几种写法及用途
好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,主要将闭包的写法.用法和用途. 一.什么 ...
- 深入理解JavaScript闭包(closure)
最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...
- 深入理解javascript闭包(一)
闭包(closure)是Javascript语言的一个难点.也是它的特色,非常多高级应用都要依靠闭包实现. 一.什么是闭包? 官方"的解释是:闭包是一个拥有很多变量和绑定了这些变量的环境的表 ...
- 深入理解javascript闭包(一)
原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...
- 深入理解Javascript闭包概念
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量 ...
- 轻松理解JavaScript闭包
摘要 闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包 一.什么是闭包? 闭包就是可以访问另一个函数作用域中变量的函数. 下面列举出常见的闭包实现方式,以例子讲解闭包概念 ...
- 【译】理解JavaScript闭包——新手指南
闭包是JavaScript中一个基本的概念,每个JavaScript开发者都应该知道和理解的.然而,很多新手JavaScript开发者对这个概念还是很困惑的. 正确理解闭包可以帮助你写出更好.更高效. ...
随机推荐
- React在开发中的常用结构以及功能详解
一.React什么算法,什么虚拟DOM,什么核心内容网上一大堆,请自行google. 但是能把算法说清楚,虚拟DOM说清楚的聊聊无几.对开发又没卵用,还不如来点干货看看咋用. 二.结构如下: impo ...
- Laravel 5.x 请求的生命周期(附源码)
Laravel最早接触是刚开始实习的时候,那时通过网上的学习资料很快便上手,开发模块接口.后来没有什么深入和总结,但是当我刚开始学Laravel的时候,我对Laravel最大的认识就是,框架除了路由. ...
- PHP-----文件系统的交互
本文讲解php中于文件交互中所使用的函数 代码示例 <html> <head> <title> File Detail </title> </he ...
- CSS知识总结(七)
CSS常用样式 5.背景样式 1)背景颜色 background-color : transparent | color 常用值:①英文单词,②十六进制,③RGB或RGBA 另外,还有一种是 渐变色彩 ...
- 【架构设计】分布式文件系统 FastDFS的原理和安装使用
本文地址 分享提纲: 1.概述 2. 原理 3. 安装 4. 使用 5. 参考文档 1. 概述 1.1)[常见文件系统] Google了一下,流行的开源分布式文件系统有很多,介绍如下: -- mo ...
- BPM应用开发解决方案分享
一.需求分析企业整体管理是一个完整的体系,如果 把这个体系比做一个拼图,企业信息化通过各个业务系统覆盖了一部分业务. 企业通过采购实施通用软件的方式,覆盖了企业的核心业务和专业化业务然而系统只满足了部 ...
- java 字节流与字符流的区别
字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作 ...
- DBobjectsCompareScript(数据库对象比较).sql
use master goIF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[func_CompareDBobjectsReColu ...
- 项目自动化建构工具gradle 入门1——输出helloWorld
先来一个简单的例子,4个步骤: 1.进入D:\work\gradle\java 目录 ,您电脑没这目录? 那辛苦自己一级一级建立起来吧 新建文件build.gradle,文件内容是: apply p ...
- Struts的拦截器
Struts的拦截器 1.什么是拦截器 Struts的拦截器和Servlet过滤器类似,在执行Action的execute方法之前,Struts会首先执行Struts.xml中引用的拦截器,在执行完所 ...