javascript闭包
时间:2022-05-07
本文章向大家介绍javascript闭包,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
## 定义
**闭包:**有权访问另一个函数作用域中的变量的函数。
## 解析
相信刚看到这个定义,很多人肯定很迷糊,现在给出示例。
```
function func1(){
var a = 1;
function func2(){
a++;
console.log(a);
};
return func2;
}
var res = func1();//等于func2
res();//等于func2(),输出2
```
首先定义了func1,func2两个函数,函数func1嵌套函数func2,然后再func1中定义变量a,再在func2中调用a。
这里的func2就是一个闭包,他有权访问func1函数中的变量。
## 作用
①可以读取函数内部的变量,且私有。
②变量可以长期驻扎在内存中。
现在我们需要实现一个变量完成计数器的任务,每次调用+1
#### 1.不使用闭包,使用全局变量完成
```javascript
var count = 1;
function func(){
count++;
console.log(count);
}
func();// 输出2
func();// 输出3
```
#### 2.不使用闭包,使用局部变量完成
```
function func(){
var count = 1;
count++;
console.log(count);
}
func();// 输出2
func();// 输出2
```
很明显,只是使用局部变量无法达成我们要求,因为局部变量有一个性质,当函数执行完毕时局部变量即刻销毁,所以我们调用两次func函数,对于变量count来说每次都是新的。上面的全局变量方法虽然能够实现要求,但是不合符数据私有安全,而且也容易造成数据交错,不利于程序的移植。
这个时候就体现出闭包的作用性了,既可以保证数据私有,又可以长期驻扎内存中不会被销毁。
```javascript
function func1(){
var count = 0;
function func2(){
count++;
console.log(count);
}
return func2;
}
var obj = func1(); // func1() ==> func2
obj(); // 1
obj(); // 2
obj(); // 3
```
## 解惑
虽然闭包的概念很好理解,但是它衍生出来的程序却不一定很好理解,下面的疑问也是博主我在学习的时候遇到的,进行总结一下。
### 1.函数数组
```javascript
function func1(){
var arr = new Array();
for(var i = 0;i<3;i++){
arr[i] = function(){
return i;
}
}
return arr;
}
var array = func1();
console.log(array[0]()); //输出3
console.log(array[1]()); //输出3
console.log(array[2]()); //输出3
```
这段程序的本意也很明了,就是新建一个数组arr,并且将值0,1,2分别赋给a[0],a[1],a[2],但是结果却出乎意料。
这里比较通俗易懂的解释是,func1中的for循环先执行匿名函数并不执行(因为没有调用),当for循环执行完毕后,在我们范围array[i]()的时候才会调用arr[i]的匿名函数,而for循环结束以后i的值为3,匿名函数中由于i并没有赋值,所以他会从外部寻找i值,而这个i值此时是3,所以arr[0-2]的值均为3。造成的主要原因就是这里所有的匿名函数都调用的同一个func1中的同一个i。所以,我们可以创建另一个匿名函数强制让闭包行为符合预期
```javascript
function func1(){
var arr = new Array();
for(var i = 0;i<3;i++){
arr[i] = function(num){
return num;
}(i);
}
return arr;
}
var array = func1();
console.log(array[0]); //输出0
console.log(array[1]); //输出1
console.log(array[2]); //输出2
```
注意下上面的输出不一样,array后面没有(),因为在匿名函数后面加了个(i),在函数后面加括号表示执行,所以此时func1()函数里面arr保存的是数值。
### 2.this问题
```javascript
var name = "The Window";
var object = {
name:"My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
}
console.log(object.getNameFunc()()); // "The Window"
```
这里暂时理解为匿名函数的执行环境具有全局性的(其他更好的答案还没发现,如果有日后在改)。
修改
```
var name = "The Window";
var object = {
name:"My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
}
console.log(object.getNameFunc()()); // "My Object"
```
这里将object的this先赋值给that,然后再匿名函数中使用that就可以找到object的this了.
**看了上面的关于this的代码,在看看下面**
```
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f() {
return scope;
}
return f();
}
console.log(checkscope()); // local scope
```
是不是混淆了,为什么上面的输出全局变量,而这段代码输出的局部变量,一定要注意上面的那个是this.name,而这里的代码只是输出变量,我们现在看看这段代码的this指向就明了了。
```
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f() {
// 输出[object Window] global scope
console.log(this + " " + this.scope);
return scope;
}
return f();
}
console.log(checkscope()); // local scope
```
所以对于this来说匿名函数总是指向window的,但是变量确实符合传递链的。所谓变量传递链就是层层向上查找,如
```
var a = 1;
function func1(){
function func2(){
console.log(a);
}
return func2;
}
func1()(); // 1
```
func2要输出a,但是func2没有,就向func1查找,发现func1也没有,就找到了全局的a。
关于全局变量还有局部变量的内容,以后还会专门写篇文章进行总结,尽情期待,由于闭包博主也是刚刚学,肯定有写的不周到的地方,希望大家能够指出,闭包的内容就到此为止。
#### 参考文献:
- [1]《javascript高级程序设计》
- [2]《javascript权威指南》
- [3] [http://www.jb51.net/article/24101.htm](http://www.jb51.net/article/24101.htm)
- 设置输出延迟
- 设置输入延时约束
- MySQL 死锁与日志二三事
- 一千个不用 Null 的理由
- TensorFlow强化学习入门(1.5)——上下文赌博机
- 以太坊·代币开发详解
- JSON Web Token - 在Web应用间安全地传递信息
- TensorFlow强化学习入门(2)——基于策略的Agents
- 用ABAP 生成二维码 QR Code
- CDS view注解解析 - @Environment.systemField
- Document flow API in SAP CRM and C4C
- Python基础知识4:文件操作
- Python基础知识6:格式化字符、颜色
- 给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler
- 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 数组属性和方法
- PHP chop()函数讲解
- Linux下安装Memcached服务器和客户端与PHP使用示例
- PHP xpath()函数讲解
- CentOS7编译安装php7.1的教程详解
- PHP addcslashes()函数讲解
- 浅谈优化Django ORM中的性能问题
- PHP chr()函数讲解
- iOS音视频接入 - TRTC常见问题
- PHP常见的几种攻击方式实例小结
- PHP strripos函数用法总结
- Laravel5.0+框架邮件发送功能实现方法图文与实例详解
- Ajax+PHP实现的删除数据功能示例
- tensorflow下的图片标准化函数per_image_standardization用法
- 浅析Python面向对象编程
- Python单元测试及unittest框架用法实例解析