JavaScript闭包详解
JavaScript闭包详解
闭包就是由函数创造的一个词法作用域,里面创建的变量被引用后,可以在这个词法环境之外自由使用(维基百科)。
闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点: 1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。 2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,JavaScript允许使用内部函数—即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
在JavaScript中,闭包通常用来创建函数内部的变量,使这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。
JavaScript中,变量的作用域只有两种:
- 全局变量
- 局部变量
这样就存在一个问题,全局变量可以被所有的函数读写,而局部变量又只能被其所有者(函数)读写。那么如果现在我们需要在外部读写改函数内部时的局部变量时我们该怎么做?
看看下面这个例子:
var add = (function (){
var count = 0;
return function() { return count += 1; }
})();
add();
add();
add();
//count为3
这就是简单的一个闭包的例子,每次调用add都会使count加1。在这个例子中,匿名函数function(){ return count += 1; }可以访问其上层匿名函数所有的局部变量,而下层匿名函数的局部变量对上层又是不可见的。这就是JavaScript特有的“链式作用结构(chain scope)”,子对象可以一层一层地向上访问所有父对象地变量,但子对象地所有变量对父对象不可见。
因此我们把下层匿名函数作为返回值,就可以在匿名函数外部读取并操作它的内部变量。
事实上,就概念而言一个函数本身就是一个闭包,但函数嵌套函数这种类型的闭包作用更大,所以我们通常所用的闭包就是一个函数内嵌套一个返回自身的函数,并提供一个变量(上面的例子是add)作为接口来调用。这样做的直观效果是我们就可以在函数外部修改函数内部的变量了。
更深层次的是,这些可修改的局部变量会一只保存在内存中。下层匿名函数被赋值给一个变量(add),这使得下层匿名函数始终存在于内存中,而它又依赖于上层匿名函数,因此闭包机构所涉及的所有函数都不会在调用结束后被垃圾回收机制(garbage collection)回收。
因此使用闭包需要注意一下两点:
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。
- 不能随便改变上层函数(父函数)内部变量的值。 常见的几种写法:
1、给函数添加一些属性
function Circle(r) {
this.r = r;
}
Circle.PI = 3.14159;
Circle.prototype.area = function() {
return Circle.PI * this.r * this.r;
}
var c = new Circle(1.0);
alert(c.area()); //3.14159
2、声明一个变量,将一个函数当作值赋给变量
var Circle = function() {
var obj = new Object();
obj.PI = 3.14159;
obj.area = function( r ) {
return this.PI * r * r;
}
return obj;
}
var c = new Circle();
alert( c.area( 1.0 ) ); //3.14159
3、这种方法使用较多,也最为方便。var obj = {}就是声明一个空的对象
var Circle={
"PI":3.14159,
"area":function(r){
return this.PI * r * r;
}
};
alert( Circle.area(1.0) );//3.14159
- React Native之常用第三方库
- React Native和Android整合详解
- 强大的API测试工具Hitchhiker v0.9 基于UI的断言测试,回顾2017
- WEB前端架构(二)
- WEB前端架构(三)
- node.js基本工作原理及流程
- Github+Jekyll搭建个人博文网站
- Ecmascript语法之Symbol
- 区块链的java实现
- gitlab操作指南
- 如何构建智能反垃圾邮件WordPress插件
- 在Mac上搭建React Native开发环境
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide图片缓存库的联系与区别
- React Native之StyleSheet样式表
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Vedastr:基于PyTorch的场景文本识别工具箱
- vue-element-admin项目关闭eslint校验
- 搞了半天,终于弄懂了TCP Socket数据的接收和发送,太难~
- 每天一个小技巧:CSS clip-path 的妙用 Clip Path分类Clippy
- 20 个值得学习的 Vue 开源项目
- 小白入门WEB前端编程,必看知识点!核心干货
- 新网站 Robots 和 SiteMap 优化
- Java代理IP池 ( Proxy Pool ) - 改进版
- Lvs+Keepalived 保障HA高可用
- 基于前端JS导出Excel文件(减轻服务端压力)
- 本机IDEA远程调试远端服务器代码
- 开源 - Java接口API授权认证与规范
- 亿及流量多级缓存 - 客户端缓存
- 亿及流量多级缓存 - 一致性哈希负载均衡与模板渲染
- 关于友情链接或者其他外部链接的建议