JavaScript 闭包

75 阅读3分钟

JavaScript闭包是指在函数内部定义的函数可以访问外部函数的变量和参数,即使外部函数已经执行完毕,这些变量和参数仍然可以被内部函数访问和使用。

闭包可以用来创建私有变量和方法,以及实现高级的函数式编程技巧。 下面是一个简单的闭包示例:

function outerFunction() { 
    var outerVariable = "Hello"; 
    
    function innerFunction() { 
        console.log(outerVariable); 
    } 
    return innerFunction; 
} 

var inner = outerFunction(); 
inner(); // 输出 "Hello" 

在这个例子中,outerFunction 返回了一个内部函数 innerFunction,并且 innerFunction 可以访问 outerVariable 变量。

outerFunction 被调用时,它创建了一个闭包,使得 outerVariable 变量在 innerFunction 中仍然可用。

下面是一些常见的闭包用法:

  1. 创建私有变量和方法 闭包可以用来创建私有变量和方法,这些变量和方法只能在函数内部访问,而外部代码无法访问。

    这种技巧可以用来隐藏实现细节,防止外部代码对内部状态进行修改。

function counter() { 
    var count = 0; 
    
    function increment() { 
        count++; 
        console.log(count); 
    } 
    
    function decrement() { 
        count--; 
        console.log(count); 
    } 
    return { 
        increment: increment, 
        decrement: decrement 
    }; 
} 

var c = counter(); 
c.increment(); // 输出 1 
c.increment(); // 输出 2 
c.decrement(); // 输出 1 

在以上这个例子中,counter 函数返回了一个对象,该对象包含两个方法 incrementdecrement,这些方法可以访问 count 变量。由于 count 变量只能在 counter 函数内部访问,所以外部代码无法修改它的值。

  1. 实现函数式编程技巧 闭包可以用来实现函数式编程技巧,例如柯里化、偏函数和高阶函数等。

    这些技巧可以使代码更加简洁和可读,同时也可以提高代码的复用性和可维护性。

function add(a, b) { 
   return a + b; 
} 
function curry(fn) { 
   return function(a) { 
       return function(b) { 
           return fn(a, b); 
       }; 
   }; 
} 
var add5 = curry(add)(5); 
console.log(add5(3)); // 输出 8 
console.log(add5(7)); // 输出 12 

在以上这个例子中,curry 函数接受一个函数 fn,并返回一个新的函数,该函数接受一个参数 a,并返回另一个新的函数,该函数接受一个参数 b,并调用 fn(a, b)。这样,我们就可以使用 curry(add)(5) 来创建一个新的函数 add5,该函数可以将 5 作为第一个参数传递给 add 函数,从而实现柯里化。

  1. 避免变量污染和命名冲突 闭包可以用来避免变量污染和命名冲突,特别是在多个 JavaScript 库或模块之间共享全局命名空间的情况下。

    通过使用闭包,每个库或模块可以创建自己的私有命名空间,从而避免与其他库或模块的命名冲突。

var myLibrary = (function() { 
    var privateVariable = "Hello"; 
    
    function privateMethod() { 
        console.log(privateVariable); 
    } 
    
    return { 
        publicMethod: function() { 
            privateMethod(); 
        } 
    }; 
})(); 

myLibrary.publicMethod(); // 输出 "Hello" 

在这个例子中,myLibrary 是一个立即执行函数,它创建了一个闭包,使得 privateVariableprivateMethod 变量只能在函数内部访问。同时,myLibrary 返回了一个对象,该对象包含一个公共方法 publicMethod,该方法可以访问 privateMethod,从而实现了私有方法的封装。