您的位置:首页 > Web前端 > JavaScript

【修真院web小课堂】js中的闭包是什么?用处如何?

2018-08-20 17:30 281 查看
版权声明:Copyright2018TianDiSheng.AllRightsReserved. https://blog.csdn.net/tianxintiandisheng/article/details/81874841

一 . 简介

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

二 . 原理剖析

1.执行环境和作用域

所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,这个执 行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。以下是关于执行环境的几 点总结:

  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
  • 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境;
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
  • 变量的执行环境有助于确定应该何时释放内存。

2.闭包的原理

当在函数内部定义了其他函数时,就创建了闭包。闭包有权访问包含函数内部的所有变量,原理如下。

  • 在后台执行环境中,闭包的作用域链包含着它自己的作用域、包含函数的作用域和全局作用域。
  • 通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。
  • 但是,当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止
  • 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

三. 更多讨论

1. 如何用闭包模仿块级作用域?

使用闭包可以在 JavaScript中模仿块级作用域(JavaScript本身没有块级作用域的概念),要点如下。
+创建并立即调用一个函数,这样既可以执行其中的代码,又不会在内存中留下对该函数的引用。
结果就是函数内部的所有变量都会被立即销毁——除非将某些变量赋值给了包含作用域(即外 部作用域)中的变量。

2.如何用闭包给对象设置私有属性?

利用闭包可以给对象设置私有属性并利用特权(Privileged)方法访问私有属性。

var Foo = function(){
var name = 'fooname';
var age = 12;
this.getName = function(){
return name;
};
this.getAge = function(){
return age;
};
};
var foo = new Foo();

foo.name; // => undefined
foo.age; // => undefined
foo.getName(); // => 'fooname'
foo.getAge(); // => 12

3. 如何理解变量销毁?

现在有一个button和一个有数字的span,button负责让数字加1,代码如下:
html部分

<body>
<button id="add">加1</button>
<span id="span">10</span>
</body>

js部分

var a = 10;
add.onclick = function (){
a++;
span.innerHTML = a;
}

每次按add按钮,就会让数字加1
现在把js部分做个改变:
例子2

add.onclick = function (){
var a = 10;
a++;
span.innerHTML = a;
}

将声明变量a这个步骤从外面挪到onclick事件函数里面的话,不管你怎么按a将永远保持11,页面的span里的数字也将永远是11,为什么?
你可能会说:因为每次按按钮的时候,我都重新声明了一个变量a啊,等于每次都重置为10了啊,每次++只能是11然后无限循环balabala。。。好,那我问你第二个问题:为什么声明a这一步写在函数外面就行了?你会说因为a一开始只声明了一次啊,每次++好的a都是在旧的a上面进行操作啊balabala。。。这个回答不能说错,但显然没有进行深入的思考,就像古时候人们都觉得苹果落地是天经地义的一样,只有保持怀疑,才有机会推导出万有引力定律。

红宝书告诉我们,没有用的局部变量就会被销毁内存,一开始我百思不得其解(没办法,没有C基础嘛),后来通过这个点击的例子就闹明白了——在你每次按好按钮,函数执行完毕后,你的这个a就被当成没有用的变量被回收了,或者换句话说,内存被销毁了!所以你的a始终都是初始的那个10!而在例子1的js代码里,a是全局变量,全局变量只有当你关闭页面or浏览器的时候才会被销毁!所以a仿佛就有了存储功能,能够记录每次变化后的值,你点或不点,a就在那乖乖的,保持着上一次点击好++的那个值。

四. 拓展思考

1、闭包与内存泄漏
JavaScript是一种高级语言,它一般是通过后台来维护这种计数系统。
当JavaScript代码生成一个新的内存驻留项时(比如一个对象或函数),系统就会为这个项留出一块内存空间。因为这个对象可能会被传递给很多函数,并且会被指定给很多变量,所以很多代码都会指向这个对象的内存空间。JavaScript会跟踪这些指针,当最后一个指针废弃不用时,这个对象占用的内存会被释放。
闭包可能会导致在不经意间创建循环引用,导致内存泄漏。

2、在闭包中的this指向问题
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定,this最终指向调用它的对象。

五.参考文献

JavaScript高级程序设计

相关链接
ppt地址
腾讯视频地址
技能树.IT修真院
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。快来与我一起学习吧~
凭邀请码注册可享受学费减免优惠
我的邀请码:25344308 ,或者你可以直接点击此链接:
修真院注册链接

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: