闭包理解
闭包理解1:闭包是嵌套的内部函数(大众理解)
function fn1 () {
var num = 10;
function fn2 () {
console.log(num)
}
}
fn1();
闭包理解2:闭包是包含被引用变量的对象(极少部分人的理解)

闭包本质:嵌套的内部函数引用了外部函数的变量
function fn1 () {
var num = 10;//外部函数定义的变量
function fn2 () {
console.log(num) //内部函数引用外部函数变量
}
}
fn1();
闭包常用使用方式1:将函数作为另一个函数的返回值
function fn1() {
var num = 10;
function fn2() {
num++;
console.log(num);
}
return fn2;
}
var f = fn1();
f(); // 11
f(); // 12
闭包常用使用方式2:将函数的形参作为实参传递给另一个函数调用
function logMsgDelay(msg, time) {
setTimeout(function () {
console.log(msg);
}, time);
}
logMsgDelay('撩课学院', 3000);
闭包作用1:使函数内部声明的局部变量在函数执行完后仍然存在
闭包作用2:使函数外部能直接访问到函数内部的局部
例如:
//闭包作用
function fn1() {
var num = 10;
function fn2() {
num++; //引用外部函数的变量--->产生闭包
console.log(num);
}
return fn2;
}
var f = fn1(); // 由于f引用着内部的函数-->内部函数以及闭包都没有成为垃圾对象
f(); // 间接操作了函数内部的局部变量
f();
理解闭包解决同步和异步
//借助小闭包, 把每次循环的i值都封闭起来
for (var i = 0; i < btns.length; i++) {
(function (i) {
var btn = btns[i];
btn.onclick = function () {
alert('第' + (i + 1) + '个')
}
})(i);
}
闭包自定义模块
//将所有的数据和功能都封装在一个函数内部(私有的)只向外暴露一个包含多个方法的对象或函数,模块的使用者, 只需要通过模块暴露的对象调用方法
来实现对应的功能
(function (window) {
// 1. 变量
var intro = ['我', '是', 'M', 'T'];
var site = 'www.itlike.com';
// 2. 操作变量的函数
function one() {
console.log(intro.join(''));
}
function two(){
console.log(site.toUpperCase());
}
window.myTool = {
fn1: one,
fn2: two
}
})(window);
console.log(window.myTool);
myTool.fn1();
myTool.fn2();
闭包使用:高级排他
1.默认的方式对li的hover事件
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';
}
}
}
2.闭包的方式对li的hover事件
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);
}
}
实现函数节流
1.普通方式(以window.onscroll事件为例)
window.onscroll = function (ev) {
console.log(11111);
}
var timer = null;
window.onresize = function (ev) {
clearTimeout(timer);
timer = setTimeout(function () {
console.log(11111);
}, 200);
};
2.闭包的方式
window.onresize = throttle(function () {
console.log(11111);
}, 200);
// 2. 将函数的形参作为实参传递给另一个函数调用
function throttle(fn, delay) {
var timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(fn, delay);
}
}