📜  JavaScript 中的闭包

📅  最后修改于: 2022-05-13 01:58:10.292000             🧑  作者: Mango

JavaScript 中的闭包

大多数 JavaScript 开发人员有意识或无意识地使用闭包。即使他们无意识地这样做,在大多数情况下也可以正常工作。但是知道闭包将在使用它们时更好地控制代码。学习闭包的另一个原因是它是 JavaScript 开发人员面试中最常见的问题。
先决条件:: JavaScript 中的变量作用域

让我们通过一个例子来看看和理解闭包。

示例 1:

Javascript
// Explanation of closure
/* 1 */        function foo()
/* 2 */         {
/* 3 */             var b = 1;
/* 4 */             function inner(){
/* 5 */                 return b;
/* 6 */             }
/* 7 */             return inner;
/* 8 */         }
/* 9 */         var get_func_inner = foo();        
 
/* 10 */         console.log(get_func_inner());
/* 11 */         console.log(get_func_inner());
/* 12 */         console.log(get_func_inner());


Javascript
/* 13 */         console.dir(get_func_inner);


Javascript
function foo(outer_arg) {
 
    function inner(inner_arg) {
        return outer_arg + inner_arg;
    }
    return inner;
}
var get_func_inner = foo(5);
 
console.log(get_func_inner(4));
console.log(get_func_inner(3));


Javascript
// Outer function
function outer()
{
    var arr = [];
    var i;
    for (i = 0; i < 4; i++)
    {
        // storing anonymous function
        arr[i] = function () { return i; }
    }
 
    // returning the array.
    return arr;
}
 
var get_arr = outer();
 
console.log(get_arr[0]());
console.log(get_arr[1]());
console.log(get_arr[2]());
console.log(get_arr[3]());


Javascript
// Outer function
function outer()
{
    function create_Closure(val)
    {
        return function()
        {
            return val;
        }
    }
    var arr = [];
    var i;
    for (i = 0; i < 4; i++)
    {
        arr[i] = create_Closure(i);
    }
    return arr;
}
var get_arr = outer();
console.log(get_arr[0]());
console.log(get_arr[1]());
console.log(get_arr[2]());
console.log(get_arr[3]());


说明:这里要注意的是从第 9行到第 12 行。在第 9 行,我们完成了函数foo()的执行,并且由于第 7 行return inner函数inner()的整个主体被返回并存储在var get_func_inner中。
[return 语句不执行内部函数——函数仅在 () 后执行,而是 return 语句返回对函数的引用,因为 JavaScript 中的函数也是一个对象。]

我们可以通过函数inner()访问函数foo()中定义的变量b ,因为后者在执行封闭函数时保留了封闭函数的作用域链,即内部函数通过其作用域链知道b的值.
这是闭包,内部函数可以访问外部函数变量以及所有全局变量。
上述代码的输出:

输出_example_1

为了查看闭包内绑定的变量和函数,我们可以写成:

Javascript

/* 13 */         console.dir(get_func_inner);

输出:

output_dir_for_function

正如我们可以在范围部分看到闭包中的变量。

闭包的定义:

或者

现在让我们看另一个例子。

示例 2:

Javascript

function foo(outer_arg) {
 
    function inner(inner_arg) {
        return outer_arg + inner_arg;
    }
    return inner;
}
var get_func_inner = foo(5);
 
console.log(get_func_inner(4));
console.log(get_func_inner(3));

说明:在上面的示例中,我们使用了参数函数而不是默认函数。请注意,即使我们完成了foo(5)的执行,我们也可以从内部函数访问outer_arg变量。并在执行内部函数时根据需要生成outer_arginner_arg的总和。

输出:

输出_example2

现在让我们看一个循环内的闭包示例。
在此示例中,我们将在数组的每个索引处存储一个匿名函数。

示例 3:

Javascript

// Outer function
function outer()
{
    var arr = [];
    var i;
    for (i = 0; i < 4; i++)
    {
        // storing anonymous function
        arr[i] = function () { return i; }
    }
 
    // returning the array.
    return arr;
}
 
var get_arr = outer();
 
console.log(get_arr[0]());
console.log(get_arr[1]());
console.log(get_arr[2]());
console.log(get_arr[3]());

输出:

输出_example_3

说明:你猜对了吗?在上面的代码中,我们创建了四个闭包,它们指向变量 i,它是函数外部的局部变量。闭包不记得变量的值,它只指向变量或存储变量的引用,因此返回当前值。在上面的代码中,当我们尝试更新它的值时,它会反映给所有人,因为闭包存储了引用。

让我们看看编写上述代码的正确方法,以便在不同索引处获得不同的 i 值。

示例 4:

Javascript

// Outer function
function outer()
{
    function create_Closure(val)
    {
        return function()
        {
            return val;
        }
    }
    var arr = [];
    var i;
    for (i = 0; i < 4; i++)
    {
        arr[i] = create_Closure(i);
    }
    return arr;
}
var get_arr = outer();
console.log(get_arr[0]());
console.log(get_arr[1]());
console.log(get_arr[2]());
console.log(get_arr[3]());

输出:

输出_example3_modified

说明:在上面的代码中,我们每次调用都会更新函数create_Closure 的参数。因此,我们在不同的索引处得到不同的 i 值。

注意:一次获得闭包的概念可能有点困难,但请尝试在不同的场景中尝试闭包,例如创建 getter/setter、回调等。