对闭包的理解(javascript)

本文深入探讨JavaScript中的闭包概念,包括词法作用域、闭包的创建和使用。通过多个示例,展示了闭包如何用于模拟私有方法、解决for循环问题以及在迭代器中的应用。闭包在函数作用域、变量持久化和封装等方面的重要性得以体现。
摘要由CSDN通过智能技术生成
定义

​ 一个函数和对其周围状态(词法环境)的引用捆绑在一起,这样的组合就是闭包。也就是说,闭包让你可以再一个内层函数中访问到其外层函数的作用域。在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

词法作用域
function init() {
  var name = "Mozilla"; // name 是一个被 init 创建的局部变量
  function displayName() { // displayName() 是内部函数,一个闭包
      alert(name); // 使用了父函数中声明的变量
  }
  displayName();
}
init();
闭包

例一:

function makeFunc(){
    var name = 'hahaha';
    function displayName(){
        alert(name);
    }
    return displayName;
}
var myFunc = makeFunc();
myFunc(); 

思考: makeFunc()执行完毕,代码仍然按照预期运行,myFunc函数相当于displayName函数绑定着var name = 'hahaha' 被返回出来了。

例二:

function add(x){
    return function(y){
        return x + y;
    }
}
var add5 = add(5);
var add10 = add(10);
//	(function(1){
// 		return 5 + 1
//	})()
console.log(add5(1)); //6 = 5 + 1
//	(function(2){
// 		return 10 + 2
//	})()
console.log(add10(2)); // 12 = 10 + 2

例三:闭包模拟私有方法

var counter = (function(){
    var private = 0;
    function change(val){
        private += val;
    }
    return {
        increment:function(){
            change(1);
        },
        decrement:function(){
            change(-1);
        },
        value:function(){
            return private;
        }
    }
})();
console.log(counter.value()); //0
counter.increment();
console.log(counter.value()); //1
counter.decrement();
console.log(counter.value()); //0

思考:每个闭包都有它自己的词法环境,例子中我们只创建了一个词法环境,为三个函数共享:counter.increment , counter.decrement , counter.value ,该环境创建于一个立即执行的函数内部,有一个私有变量private,一个私有函数change, 他们不能在函数外面访问,只能通过 return出去的三个函数访问,这个三个return出去的函数是共享同一个环境的闭包。

例三的扩展:

var counter = function(){
    var private = 0;
    function change(val){
        private += val;
    }
    return {
        increment:function(){
            change(1);
        },
        decrement:function(){
            change(-1);
        },
        value:function(){
            return private;
        }
    }
};
var counter1 = counter();
var counter2 = counter();
console.log(counter1.value()); //0
counter1.increment();
counter2.increment();
console.log(counter1.value()); //1
counter1.decrement();
// 说明了两个闭包的环境相互独立,各自维护自己的词法作用域
console.log(counter1.value()); //0 
console.log(counter2.value()); //1 

例四:使用闭包解决for循环问题

for (var i = 0; i < 5; i++) {
    // 每个setTimeout里面的回调函数都有共同的环境变量i
    setTimeout(() => {
        console.log(i)
    },0)
}
// 5,5,5,5,5,5

思考:因为var没有块级作用域,使用setimeout后,宏任务执行console.log的时候,i在主线程结束时候已经变成了5。

解决方法

// 使用闭包的方法
for (var i = 0; i < 5; i++) {
    let time = function(x){
        // 每个setTimeout里面的回调函数都有自己的环境变量x,维护各自的环境变量
        setTimeout(() => { 
        	console.log(x)
    	},0)
    };
    time(i); 
}
//使用块级作用域
for (let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(x)
    },0)
}
// 1,2,3,4,5

例五 理解迭代器原理

function iterator (items) {
  let i = 0;
  return function () {
    return items[i++]
  }
}
var next = iterator( [1, 2, 3, 4] ); 
//以下的next都共用一个词法环境,共用一个变量i
console.log(next()); // 1
console.log(next()); // 2
console.log(next()); // 3 
console.log(next()); // 4
console.log(next()); // undefined
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值