71muke?v=1
在线看书
立即购买

第一章 前言

收起
2024-08-14更新,每天更一篇

第二章 JavaScript高级语言特性

收起
2024-08-14更新,每天更一篇

第三章 面向对象编程(OOP)深入探讨

收起
2024-08-14更新,每天更一篇

第四章 JavaScript模块化

收起
2024-08-14更新,每天更一篇

第五章 深入理解JavaScript引擎

收起
2024-08-14更新,每天更一篇
71muke 71muke

闭包

闭包(Closure)的详细内容

1. 什么是闭包?

闭包是指在一个函数内部定义另一个函数时,内部函数可以访问其外部函数的变量和参数,即使外部函数已经执行完毕并且其作用域已被销毁。闭包使得内部函数“记住”了外部函数的上下文。

通俗地说,闭包可以让一个函数在其作用域之外记住并访问到其定义时的环境中的变量。

2. 闭包的形成条件

  • 必须有嵌套的函数。

  • 内部函数引用了外部函数的变量。

  • 外部函数已经执行完毕并返回了内部函数。

3. 闭包的优点

  • 数据封装:通过闭包,可以创建私有变量,外部无法直接访问这些变量,只能通过内部函数进行操作,从而实现数据封装。

  • 持久化数据:闭包可以让一个函数记住它执行时的环境,使得一些数据在外部函数执行完毕后仍然保持持久化。

4. 闭包的缺点

  • 内存消耗:由于闭包会使得函数内部的变量一直保存在内存中,可能会导致内存泄漏,因此在使用闭包时要小心,尽量避免过度使用或使用不当。

  • 调试复杂:闭包使得变量作用域链变得复杂,调试时很难看清楚变量的来源,尤其在深度嵌套的情况下。

5. 闭包的案例

案例 1:基本闭包示例
function createCounter() {
    let count = 0;
    return function() {
        count += 1;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 输出: 1
console.log(counter()); // 输出: 2
console.log(counter()); // 输出: 3

解释:在这个例子中,createCounter函数返回了一个匿名函数,该匿名函数引用了外部函数createCounter中的变量count。每次调用counter()时,count的值都会增加并且保存在内存中。尽管createCounter已经执行完毕,但由于闭包的存在,count变量依然可以被访问和修改。

案例 2:实现私有变量
function createPerson(name) {
    let _name = name;
    
    return {
        getName: function() {
            return _name;
        },
        setName: function(newName) {
            _name = newName;
        }
    };
}

const person = createPerson('Alice');
console.log(person.getName()); // 输出: Alice
person.setName('Bob');
console.log(person.getName()); // 输出: Bob

解释:在这个例子中,_name变量被封装在createPerson函数内部,外部无法直接访问或修改这个变量。只能通过getNamesetName方法访问或修改_name。这就是利用闭包实现数据封装的一个例子。

6. 闭包的练习题

以下是一些练习题,帮助您更好地理解和掌握闭包的概念。

练习题 1:求和函数

编写一个函数createAdder,它接受一个数字x作为参数,并返回一个新函数。这个新函数接受一个数字y作为参数,并返回x + y的值。

function createAdder(x) {
    // 在此处实现
}

const add5 = createAdder(5);
console.log(add5(10)); // 输出: 15
console.log(add5(20)); // 输出: 25

答案:

function createAdder(x) {
    return function(y) {
        return x + y;
    };
}

const add5 = createAdder(5);
console.log(add5(10)); // 输出: 15
console.log(add5(20)); // 输出: 25
练习题 2:延迟函数调用

编写一个函数delayedGreeting,它接受一个字符串name作为参数,并返回一个新函数。调用该新函数时,会在1秒后输出"Hello, name!"。

function delayedGreeting(name) {
    // 在此处实现
}

const greet = delayedGreeting('Alice');
greet(); // 输出: "Hello, Alice!" (延迟1秒)

答案:

function delayedGreeting(name) {
    return function() {
        setTimeout(function() {
            console.log(`Hello, ${name}!`);
        }, 1000);
    };
}

const greet = delayedGreeting('Alice');
greet(); // 输出: "Hello, Alice!" (延迟1秒)
练习题 3:计数器模块

编写一个counterModule函数,它返回一个对象,对象中有incrementdecrementgetValue三个方法,可以分别增加、减少和获取计数值。

function counterModule() {
    // 在此处实现
}

const counter = counterModule();
counter.increment();
counter.increment();
console.log(counter.getValue()); // 输出: 2
counter.decrement();
console.log(counter.getValue()); // 输出: 1

答案:

function counterModule() {
    let count = 0;
    
    return {
        increment: function() {
            count += 1;
        },
        decrement: function() {
            count -= 1;
        },
        getValue: function() {
            return count;
        }
    };
}

const counter = counterModule();
counter.increment();
counter.increment();
console.log(counter.getValue()); // 输出: 2
counter.decrement();
console.log(counter.getValue()); // 输出: 1

这些练习题旨在帮助您通过动手实践,深入理解闭包的概念及其应用。通过多次练习,您将能在实际开发中熟练运用闭包,解决各种编程问题。

留言

发布留言

需要购买本课才能留言哦~

{{ item.createtime | dateStr }}
×