一、闭包是什么?一个简单的例子
function outer() {
    let me = '小杨';
    return function inner() {
        console.log(`大家好,我是${me}`);
    };
}
const sayHello = outer();
sayHello(); 
看到没?inner函数记住了outer函数的me变量,这就是闭包!
二、闭包的三大妙用(天使面)
1. 创建私有变量
function createCounter() {
    let count = 0;
    return {
        increment() { count++ },
        getCount() { return count }
    };
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); 
console.log(counter.count); 
2. 实现函数柯里化
function multiply(a) {
    return function(b) {
        return a * b;
    };
}
const double = multiply(2);
console.log(double(5)); 
3. 事件处理中的妙用
function setupButtons() {
    for(var i = 1; i <= 3; i++) {
        (function(index) {
            document.getElementById(`btn-${index}`)
                .addEventListener('click', function() {
                    console.log(`我是按钮${index}`);
                });
        })(i);
    }
}
三、闭包的三大坑(魔鬼面)
1. 内存泄漏
function leakMemory() {
    const bigData = new Array(1000000).fill('*');
    return function() {
        console.log('我还记得bigData');
    };
}
const leaked = leakMemory();
2. 性能问题
function slowPerformance() {
    const data = {}; 
    return function(key, value) {
        data[key] = value;
        
    };
}
3. 意外的变量共享
function createFunctions() {
    let funcs = [];
    for(var i = 0; i < 3; i++) {
        funcs.push(function() {
            console.log(i); 
        });
    }
    return funcs;
}
四、闭包优化六大法则(6年经验总结)
1. 及时释放引用
function createHeavyObject() {
    const heavy = new Array(1000000).fill('*');
    return {
        useHeavy: function() {
            
        },
        cleanup: function() {
            heavy = null; 
        }
    };
}
2. 使用块级作用域
function createFixedFunctions() {
    let funcs = [];
    for(let i = 0; i < 3; i++) { 
        funcs.push(function() {
            console.log(i); 
        });
    }
    return funcs;
}
3. 避免不必要的闭包
function unneededClosure() {
    const data = {};
    return function() {
        
        console.log('Hello');
    };
}
function noClosure() {
    console.log('Hello');
}
4. 使用WeakMap管理私有变量
const privateData = new WeakMap();
class MyClass {
    constructor() {
        privateData.set(this, {
            secret: '我是私有数据'
        });
    }
    
    getSecret() {
        return privateData.get(this).secret;
    }
}
5. 合理使用IIFE
(function() {
    const tempData = processData();
    
})(); 
6. 使用模块化
const counterModule = (function() {
    let count = 0;
    
    return {
        increment() { count++ },
        getCount() { return count }
    };
})();
五、真实案例分享
案例1:我曾经在项目中遇到一个页面卡顿问题,最后发现是因为一个事件处理函数形成了闭包,持有了一个大DOM树的引用。解决方案是:
function setup() {
    const bigElement = document.getElementById('big');
    button.addEventListener('click', function() {
        
        console.log(bigElement.id);
    });
}
function setup() {
    const id = 'big';
    button.addEventListener('click', function() {
        
        console.log(id);
    });
}
六、总结
闭包就像一把双刃剑:
✅ 优点:实现私有变量、函数柯里化、模块化等
❌ 缺点:可能导致内存泄漏、性能问题
记住我的6年经验总结:
- 及时释放不再需要的引用
- 优先使用块级作用域
- 避免不必要的闭包
- 合理使用WeakMap和模块化
- 善用开发者工具检查内存
转自https://juejin.cn/post/7512259761196957707
该文章在 2025/6/6 9:18:57 编辑过