当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包(closure)javascript
使用chrome调试查看java
理解一: 闭包是嵌套的内部函数chrome
理解二: 包含被引用变量(函数)的对象闭包
注意: 闭包存在于嵌套的内部函数中异步
函数嵌套函数
内部函数引用了外部函数的数据(变量/函数)性能
// 1. 将函数做为另外一个函数的返回值 function fn1() { var num = 10; function fn2() { num++; console.log(num); } return fn2; } // 经过全局变量引用, 保住了内部函数fn2的命 var f = fn1(); f(); // 11 在外部函数执行完成后, 还能够执行内部函数 f(); //
// 2. 将函数的形参做为实参传递给另外一个函数调用 function logMsgDelay(msg, time) { setTimeout(function () { console.log(msg); }, time) }
封闭做用域又称值为封闭空间,还有一个昵称叫小闭包,以及匿名函数自调。this
<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); }
做用域链条
JS中有不少做用域, 好比: 全局做用域 和 局部做用域指针
把一些不须要暴露在全局的变量封装成"私有变量"调试
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>
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>
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); } }
前面的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); } }
function fn1() { var arr = new Array[999999999]; function fn2() { console.log(arr.length) } return fn2 } var f = fn1(); f(); f = null //让内部函数成为垃圾对象-->回收闭包
一种程序运行出现的错误
当程序运行须要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
var arrObj = {}; for (var i = 0; i < 10000; i++) { arrObj[i] = new Array(9999999999999); console.log(arrObj); }
占用的内存没有及时释放
内存泄露积累多了就容易致使内存溢出
常见的内存泄露:
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