js语法深入四:史上最简洁最准确的闭包描述
来源:互联网 发布:数控车螺纹编程 编辑:程序博客网 时间:2024/05/26 08:43
上一篇《对js函数的理解及深入讨论》
谈起闭包很多人都会挠头。我以前也是,因此我查阅了很多资料,综合分析和理解,自认现在已经识得了闭包的真面目。下面我就从闭包的产生条件,闭包的作用,闭包的实质,闭包的本质,闭包产生的时机,闭包的应用 等几个方面具体和系统的阐述一下闭包。
前导
我们谈闭包有一个前提条件:
一般情况下,函数执行完毕,它内部的变量会被销毁。
现在我们在来看
闭包是一种语言特性,可以使嵌套的内部函数访问并保存嵌套的外部函数的局部变量。外部函数执行完后,只要内部函数还存在,那其中保存外部函数的局部变量也会保存下来。可能看这句话有些绕,咱们往下看
闭包产生的条件:
1 存在函数嵌套,函数fun2在函数fun1执行时被定义,我们认为fun2是fun1的内部函数。
2 内部函数引用了外部函数的局部变量。
3 内部函数被暴露出来,可以在外部函数外调用,内部函数中访问的外部函数的局部变量被保存下来,就形成了闭包。
闭包的作用:
1.延长了局部变量的生命周期
2.在函数外可以间接操纵内部局部变量
闭包的本质:
一种语言特性,在浏览器的具体实现中是内部函数对象内部的一个隐式对象【Closure】,用以保存内部函数引用的外部函数的局部变量。
(隐式变量:存在于浏览器内存中,帮助完成语法功能,但不能被程序员操作的对象)
如果有兴趣可以用chrome开发者工具中Sources指令查一下函数执行时的栈结构附上一段调试代码
function fn1 () { var a = 2 var b = 'abc' function fn2 () { console.log(a) } } fn1()
闭包产生的时机:
访问了外部函数局部变量的内部函数被定义时产生了闭包。闭包的生命周期取决于内部函数的生命周期。
闭包到底是内部函数被定义是产生,还是被暴露出去的时候产生?
经常有人会纠结这个问题,其实两者说的都有道理,内部函数定义时就产生了闭包。但此时内部函数也是被外部函数的变量指向的。如果不把内部函数对象暴露出去,那等函数执行完内部变量对象也就被销毁了,闭包也无从谈起。
闭报的应用:
说起闭包,我们通常的认识这是一个高级语法,最大的作用就是提高逼格。
非也非也,其实我们也js代码从来没有离开过闭包。
我们曾经长期使用的Jq框架,就是必报的有力实践者。大家知道的,先进大部分的框架和模块都是用IIFE封装的。所以我们使用的方法和属性都是这个自调用函数的内部变量。
我们使用的$的方法中有保存着大量的IIFE的内部资源。这变量都保存在暴露出来的方法的闭包中。
我们在写较复杂的原生代码时也经常会使用到闭包,只是我们不经意而已。这就是所谓的语法糖。
案例
闭包的魅力和招人恨的的能力,从来不是因为这个概念有多难理解。而是它可以让代码有很多“玩法”,这些玩法通常会颠覆我们的直觉
案例一:
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());//这个很简单,且没有应用到闭包,稍微有点难点的就是object.getNameFunc()是作为一个全局函数被调用的所以,他的this指向window。关于this稍微啰嗦一句,this是函数代码执行前js引擎预定义的一个变量,这个变量指向调用该函数或者所方法的对象。说白了,正在执行的函数是谁调用的,他里面的this就指向谁。
案例二:
var name2 = "The Window"; var object2 = { name2 : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name2; }; } }; alert(object2.getNameFunc()()); //? my object 内部函数保存外部函数的局部变量that。
案例三:
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n) } }} var a = fun(0) //(1) a.fun(1) //(2) a.fun(2) //(3) a.fun(3)//undefined,0,0,0 //(4) var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2 //(5) var c = fun(0).fun(1) //(6) c.fun(2) //(7) c.fun(3)//undefined,0,1,1 //(8) 这个题很有意思,我建议看到这里的小伙伴试着做一做。 下面我们一行一行的解析一下 (1)先看输出了啥,o传实参,所以o为undefined,打印undefined; 再看返回什么,返回一个对象,这个对象中有一个方法fun。 { fun:function(m){ return fun(m,n) } } 此时a指向这个对象。 (2)a.fun方法是第一次执行是被定义的,且a.fun访问了fun函数的局部变量n。 此后在怎执行a.fun一直指向原来的函数。也就是说a.fun的闭包中始终有一个n = 0; 所以后面三条语句是fun函数执行了三次,分别是fun(1,0);fun(2,0);fun(3,0) (5)第一个fun(0) 实在执行一个函数fun,与(1)相同, 输出undefined fun(0).fun(1) 与(2)相同,输出 0;但其返回一个新的对象,这个对象中的方法与a.fun不指向 同一个函数对象了。这个方法闭包中的n是访问第二次fun(m,n)函数的内部变量得来的,所以此时n=1; 故fun(0).fun(1).fun(2) 输出1 同理fun(0).fun(1).fun(2).fun(3) 再输出一个3; (6)同(1)(2)输出 undefined 和 0;并且返回的对象中fun方法的闭包中保存着n=1; (7)(8) 调用的是同一个方法 都输出1
- js语法深入四:史上最简洁最准确的闭包描述
- 最简洁的技文语法着色代码(css+js)
- 最简洁的JS时钟代码
- 关于js的日历表(最简洁)
- [JS 最简单简洁的插件] 对话框
- js 闭包说的很简洁
- JS闭包的深入理解
- js最强大,最简洁的【禁止输入中文】
- 最简洁的HTML JS树形带复选框
- [JS 最简单简洁的插件] 表格排序
- [JS 最简单简洁的插件] 表格行伸缩
- [JS 最简单简洁的插件] 表单验证
- js禁止中文输入 最简洁的【禁止输入中文】
- 最简洁的秒杀 "阿里月饼" js脚本
- 简单描述js闭包概念
- JS闭包深入详解
- JS闭包深入详解
- js闭包深入详解
- React组件refs详解
- 分析包信息
- 17-6-26前端电子书籍出处分享
- java基础:对象
- 自定义的spinnerView
- js语法深入四:史上最简洁最准确的闭包描述
- git fabric 1.0.0 官方源码进行编译,生成 docker images(rc2 版本2017年6月26日)
- JavaScript学习总结——Javascript原型链的原理
- 买房子还是朝南的好
- BufferedImage 类使用
- 高可用复用对象的设计
- Thinkphp网站全真静态解决方案
- 各种效果
- 【JVM】线程安全与锁优化