JS闭包解析
三点注意事项
- JS没有块级作用域,只有全局作用域和局部作用域(函数作用域)。
- JS中的作用域链,内部的作用域可以访问到外部作用域中的变量和方法,而外部作用域不能访问内部作用域的变量和方法。
- 当前作用域没有此变量或方法,会向外部作用域寻找变量或方法。
闭包的两种使用场景
函数作为返回值
function f() {
var a = 100;
return function () {
console.log(a);
}
}
var fn = f();
var a = 200;
fn(); // 输出100
调用fn函数,输出a的值,fn中并没有定义a,所以会向上找a,在f函数的作用域中,有a,值为100。所以就会输出100,并不会输出200。全局作用域中的a和f函数作用域中的a并不相同。这也体现出了闭包的一个好处:不会造成全局变量污染。
函数作为参数
function f() {
var a = 100;
return function () {
console.log(a);
}
}
var fn = f();
function f2(fn) {
var a = 200;
fn();
}
f2(fn);// 输出100
调用f2函数,传入fn函数,调用fn函数,输出a为100。
关于for循环和闭包之间的关系
var arr = [];
var i;
for (i = 0; i < 3; i++) {
arr[i] = function () {
return i;
}
}
console.log(arr[0]()); // 输出2
arr[0]()的结果,按照一般的思路来讲,应该是0才对,为什么是2呢?
- for循环3次,i的值从0变为2,arr这个数组中也添加了3个函数。
- 当调用
arr[0]函数时,for循环已经结束了,这时候i的值已经为2了,所以arr[0]函数取到的值为2。
如何解决这个问题?
var arr = [];
var i;
for (i = 0; i < 3; i++) {
arr[i] = (function (i) {
return function () {
return i;
}
})(i);
}
console.log(arr[0]()); // 输出0
这里,使用自执行匿名函数构造成一个独立作用域。每一次for循环的时候,都会执行这个匿名函数,并生成 一个匿名函数作用域。
比如第一次循环的时候,i = 0,将i作为参数传入匿名函数中,这样i的值就被保存在匿名函数作用域中。当调用arr[0]函数时,arr[0]就会取到匿名函数中的i的值。
闭包的实际应用
// 闭包实际应用中主要是封装变量,收敛权限
function isFirstLoad() {
var _list = [];
return function (id) {
if (_list.indexOf(id) > 0) {
return false;
} else {
_list.push(id);
return true;
}
}
}
var firstLoad = isFirstLoad();
firstLoad(1); // 返回true
firstLoad(1); // 返回false
firstLoad(2); // 返回true
闭包的缺点
目前主流浏览器采用的垃圾收集策略均为标记清除。当变量进入环境(比如,定义一个变量)时,就将这个变量标记为‘进入环境’,当变量离开环境时,就会被标记为‘离开环境’,就会被销毁。在刚才的闭包实际应用中_list变量一直被isFirstLoad的返回函数引用着,不会随着isFirstLoad的调用结束而销毁。所以_list变量会一直存在内存中。因此不能滥用闭包,否则就会造成网页性能问题,甚至内存泄漏。当我们不需要这些变量的时候,我们可以把这些变量的值赋值为null。
JS闭包解析的更多相关文章
- JS的解析与执行过程
JS的解析与执行过程 全局中的解析和执行过程 预处理:创建一个词法环境(LexicalEnvironment,在后面简写为LE),扫描JS中的用声明的方式声明的函数,用var定义的变量并将它们加到预处 ...
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
- js闭包之初步理解( JavaScript closure)
闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...
- JS的解析机制
JS的解析机制,是JS的又一大重点知识点,在面试题中更经常出现,今天就来唠唠他们的原理.首先呢,我们在我们伟大的浏览器中,有个叫做JS解析器的东西,它专门用来读取JS,执行JS.一般情况是存在作用域就 ...
- (原创)JS闭包看代码理解
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- js闭包理解
js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...
- js的解析--预处理(三)
js的解析与执行过程 分全局 {预处理阶段和执行阶段} 函数{预处理函数和执行阶段} 1/创建词法环境(环境上下文) LexicalEnvironment === window { } ...
随机推荐
- 洛谷 P1045 & [NOIP2003普及组] 麦森数
题目链接 https://www.luogu.org/problemnew/show/P1045 题目大意 本题目的主要意思就是给定一个p,求2p-1的位数和后500位数. 解题思路 首先看一下数据范 ...
- 使用Postman测试https接口时的小问题记录
测试本地的WebApi接口时,接口是https,自己写的用httpclient测试是可以的, 用postman一直连接不了.原因正是由于https,不过postman在界面上已经给出了可能的原因和解决 ...
- 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)
需要说明一点,要成功运行本贴代码,需要重新复制我第一篇随笔<简单的循环队列>代码(版本有更新). 进入今天的主题. 今天这篇文章主要探讨广度优先搜索(BFS)结合队列和深度优先搜索(DFS ...
- PHP实现域名授权的两种方法-转
01. 在线校验域名授权的方法: 客户端代码: PHP <?php //获取不带端口号的域名前缀 $servername = trim($_SERVER['SERVER_NAME'] ...
- Linux 重定向 2>&1 , 1>&2
在 shell 程式中,最常使用的 FD (file descriptor) 大概有三个, 分别是: 0 是一个文件描述符,表示标准输入(stdin)1 是一个文件描述符,表示标准输出(stdout) ...
- [转] 初探webpack4
一.前言 2018/2/25,webpack4正式发布,距离现在已经过去三个多月了,也逐渐趋于稳定,而且现在的最新版本都到了4.12.0(版本迭代快得真是让人害怕). 很多人都说webpack复杂,难 ...
- openssl私钥转换为PKCS8
先装openssl 原来 -----BEGIN DSA PRIVATE KEY----- 转换后 -----BEGIN PRIVATE KEY----- openssl pkcs8 -topk8 -i ...
- .Net Core小技巧 - Swagger适配虚拟目录及二级目录
前言 随着前后端分离模式与微服务架构的出现,Web API变得越来越重要及普遍.而后出现的网关技术,使开发者更倾向于使用二级/多级目录来暴露Web API,一是暴露的端口更少,方便管理:二是在网关中可 ...
- Linux中的官方源、镜像源汇总
转载一篇文章,很有用 (一).企业站 搜狐: http://mirrors.sohu.com/ 网易: http://mirrors.163.com/ 阿里云: http://mirrors.aliy ...
- Schedule Problem spfa 差分约束
题意:有n个任务,给出完成n个任务所需时间,以及一些任务安排.任务安排有四种: FAS a b:任务a需在任务b开始后完成. FAF a b:任务a需在任务b完成后完成. SAF a b:任务a需在任 ...