JS高级:闭包
1 如何产生闭包?
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包(closure)
2 闭包到底是什么?
使用chrome调试查看
理解一: 闭包是嵌套的内部函数
理解二: 包含被引用变量(函数)的对象
注意: 闭包存在于嵌套的内部函数中
3 产生闭包的条件?
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
4 常见的闭包使用形式?
4.1 将函数作为另一个函数的返回值
// 1. 将函数作为另一个函数的返回值
function fn1() {
var num = 10;
function fn2() {
num++;
console.log(num);
}
return fn2;
}
// 通过全局变量引用, 保住了内部函数fn2的命
var f = fn1();
f(); // 11 在外部函数执行完成后, 还可以执行内部函数
f(); //
4.2 将函数的形参作为实参传递给另一个函数调用
// 2. 将函数的形参作为实参传递给另一个函数调用
function logMsgDelay(msg, time) {
setTimeout(function () {
console.log(msg);
}, time)
}
5 闭包的作用分析
- 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
6 理解闭包解决同步和异步
封闭作用域又称值为封闭空间,还有一个昵称叫小闭包,以及匿名函数自调。
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
/*
封闭作用域又称值为封闭空间,还有一个昵称叫小闭包,以及匿名函数自调。
写法:
(function(){})();
;(function(){})();
+(function(){})();
-(function(){})();
*/
var btns = document.getElementsByTagName('button');
/*
借助小闭包, 把每次循环的i值都封闭起来
*/
for (var i = 0; i < btns.length; i++) {
console.log('全局的i:' + i);
(function (i) {
console.log('局部的i:' + i);
var btn = btns[i];
btn.onclick = function () {
alert('第' + (i + 1) + '个')
}
})(i);
}
7 模块封装(封装全局变量)
作用域链条
JS中有很多作用域, 比如: 全局作用域 和 局部作用域
- 凡是存在作用域的地方一定有作用域链条, 变量的查找都是沿着这条链条自内而外的;
- 寻找变量都是递归遍历寻找, 当前作用域找不到, 就跳到上一个作用域遍历寻找, 直至顶层;
- 作用域链条太长, 会影响程序运行效率
把一些不需要暴露在全局的变量封装成"私有变量"
7.1 私有模块封装
MyTool1.js
function myTool() {
// 1.私有数据
var money = 1000;
// 2. 操作数据的函数
function get() {
money++;
console.log('赚了一笔钱, 总资产: ' + money + '元');
}
function send() {
money--;
console.log('花了一笔钱, 总资产: '+ money + '元');
}
//向外暴露对象(给外部使用的方法)
return {
'get': get,
'send': send
}
}
调用
<script type="text/javascript" src="js/MyTool1.js"></script>
<script type="text/javascript">
var tool = myTool();
tool.get();
tool.send();
</script>
7.2 全局模块(window)封装
MyTool2.js
;(function (window) {
// 1.私有数据
var money = 1000;
// 2. 操作数据的函数
function get() {
money++;
console.log('赚了一笔钱, 总资产: ' + money + '元');
}
function send() {
money--;
console.log('花了一笔钱, 总资产: '+ money + '元');
}
//向外暴露对象(给外部使用的方法)
window.myTool = {
get: get,
send: send
}
})(window);
/*
性能考虑, 作用域链条是递归查找对象的
压缩考虑, a,b,c,...
*/
调用
<script type="text/javascript" src="js/MyTool2.js"></script>
<script type="text/javascript">
myTool.get();
myTool.send();
</script>
8 场景应用
8.1 高级排他
2个for循环,改为设置1个,根据下标清除
// window.onload = function () {
// var allLis = document.getElementsByTagName('li');
// for(var i=0; i<allLis.length; i++){
// var li = allLis[i];
// li.onmouseover = function () {
// for(var j=0; j<allLis.length; j++){
// allLis[j].className = '';
// }
// this.className = 'current';
// }
// }
// }
window.onload = function () {
var allLis = document.getElementsByTagName('li');
// 记录移动前选中li对应的索引
var preSelectLiIndex = 0;
for(var i=0; i<allLis.length; i++){
(function (i) {
var li = allLis[i];
li.onmouseover = function () {
// 清除
allLis[preSelectLiIndex].className = '';
// 设置
this.className = 'current';
// 赋值
preSelectLiIndex = i;
}
})(i);
}
}
8.2 函数节流
前面的timer作为全局变量,window指针指向它,如果有很多,影响性能。
/*
var timer = null;
window.onresize = function () {
clearTimeout(timer);
timer = setTimeout(function () {
console.log('输出的内容!!!!');
}, 200);
}
*/
window.onresize = throttle(function () {
console.log('大家好!!!');
}, 200);
function throttle(fn, delay) {
var timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(fn, delay);
}
}
9 闭包的缺点
- 缺点
函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
容易造成内存泄露 - 解决
及时释放
function fn1() {
var arr = new Array[999999999];
function fn2() {
console.log(arr.length)
}
return fn2
}
var f = fn1();
f();
f = null //让内部函数成为垃圾对象-->回收闭包
10 内存管理
10.1 内存溢出
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
var arrObj = {};
for (var i = 0; i < 10000; i++) {
arrObj[i] = new Array(9999999999999);
console.log(arrObj);
}
10.2 内存泄露
占用的内存没有及时释放
内存泄露积累多了就容易导致内存溢出
常见的内存泄露:
1. 占用内存很大的全局变量
2. 没有及时清理的计时器/定时器
3. 闭包
// 2. 内存泄露
// 2.1 占用内存很大的全局变量
/*
var num = new Array(9999999999999);
console.log(num);
*/
// 2.2 没有及时清理的计时器或回调函数
/*
var intervalId = setInterval(function () { //启动循环定时器后不清理
console.log('----')
}, 1000);
clearInterval(intervalId);
*/
// 2.3 闭包
/*function fn1() {
var num = 111;
function fn2() {
console.log(num--);
}
return fn2
}
var f = fn1();
f();*/
// f = null
JS高级:闭包的更多相关文章
- JS高级——闭包
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- js高级-闭包
function foo(x){ var tmp = 3; return function(y){ //把一个函数作为返回值,定义时候的作用域 console.log(x+y+(++tmp)) //+ ...
- JS高级——闭包练习
从上篇文章我们知道与浏览器的交互操作如鼠标点击,都会被放入任务队列中,而放入到任务队列中是必须等到主线程的任务都执行完之后才能执行,故而我们有时利用for循环给dom注册事件时候,难以获取for循环中 ...
- JS高级---闭包小案例
闭包小案例 普通的函数 //普通的函数 function f1() { var num = 10; num++; return num; } console.log(f1()); //11 conso ...
- 《Node.js 高级编程》简介与第二章笔记
<Node.js 高级编程> 作者简介 Pedro Teixerra 高产,开源项目程序员 Node 社区活跃成员,Node公司的创始人之一. 10岁开始编程,Visual Basic.C ...
- 理解运用JS的闭包、高阶函数、柯里化
JS的闭包,是一个谈论得比较多的话题了,不过细细想来,有些人还是理不清闭包的概念定义以及相关的特性. 这里就整理一些,做个总结. 一.闭包 1. 闭包的概念 闭包与执行上下文.环境.作用域息息相关 执 ...
- js高级-面向对象继承
一.工厂模式创建对象及优缺点 继承就是把公共的部分抽象出来作为父类,基类.吃饭,跑步等 var a = {}; //批量创建不方便,不能重复设置公共属性的代码 //工厂模式出现了,创建10个Cat对象 ...
- [ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
原网址:https://segmentfault.com/a/1190000002778015 1. 什么是闭包? 来看一些关于闭包的定义: 闭包是指有权访问另一个函数作用域中变量的函数 --< ...
- js高级---js架构
ECMAScript1997 年欧洲计算机制造商协会 39 号技术委员会制定了ECMA-262标准(别名 ECMAScript),而浏览器只是负责实现,ie浏览器实现的结果是jscript,远景浏览器 ...
- JS的闭包、高阶函数、柯里化
本文原链接:https://cloud.tencent.com/developer/article/1326958 https://cloud.tencent.com/developer/articl ...
随机推荐
- Windows10家庭版安装docker攻略
在公司,一直使用mac系统,在mac上安装使用docker还是比较方便的,可本人心血来朝,家里是win10 home版,就想在windows上刷一刷. 好了,废话不多说,直接上干货. 为了不误导广大爱 ...
- 【Feign调用异常】org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
一.异常场景描述 明明是post请求,为啥到达服务器后就变成了get请求 2019-05-30 18:07:17.055 [http-nio-10650-exec-4] ERROR c.x.xcaut ...
- matplotlib setting zh-hans
from matplotlib import pyplot as plt from matplotlib import font_manager import random # you font fa ...
- Docker万字详解!
一.简介 1.了解Docker的前生LXC LXC为Linux Container的简写.可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性.相当于C+ ...
- python爬虫中的ip代理设置
设置ip代理是爬虫必不可少的技巧: 查看本机ip地址:打开百度,输入“ip地址”,可以看到本机的IP地址: 本文使用的是goubanjia.com里面的免费ip: 使用时注意要注意传输协议是http还 ...
- unicode转换为中文
unicode转换为中文 \u5f53\u5730\u65f6\u95f42019\u5e747\u670813\u65e5\uff0c\u82f1\u56fd\u8d1d\u5fb7\u798f\u ...
- LOJ#2343. 「JOI 2016 Final」集邮比赛 2
题目地址 https://loj.ac/problem/2343 题解 首先处理出\(f[i]\)表示以当前位置开头(J,O,I)的合法方案数.这个显然可以\(O(n)\)处理出来.然后考虑在每个位置 ...
- 通过jekyll在Github 搭建个人博客
能快乐旅行的人,一定是轻装旅行的人 前言 应广大的网友(装逼~~哈哈)要求,决定写个Jekyll+Giuhub搭建博客的教程,以便帮助更多的人,毕竟我也是这么过来的.这是我的博客地址,可以先看看效果. ...
- hdu1171&&P2000——母函数
hdu1171 题意:有 $n$ 种设施,每种有价值 $v_i$ 和数量 $m_i$,求一种方案使得分成价值尽可能相近的两组.($n \leq 50, v_i \leq 50, m_i \leq 10 ...
- rust cargo 一些方便的三方cargo 子命令扩展
内容来自cargo 的github wiki,记录下,方便使用 可选的列表 cargo-audit - Audit Cargo.lock for crates with security vulner ...