JavaScript——可变范围和关闭

在JavaScript中,您在使用变量之前先声明它们:var

> var x;

> x

未定义

> y

ReferenceError:y未定义

您可以使用一个var 语句来声明和初始化几个变量:

var x = 1, y = 2, z = 3;

但是我建议每个变量使用一个语句(原因在Syntax中进行了解释)。因此,我将前面的语句重写为:

var x = 1;

var y = 2;

var z = 3;

由于提升(请参见变量提升),通常最好在函数的开头声明变量。

变量是函数范围的

变量的范围始终是完整的功能(与当前块相反)。例如:

function foo() {

    var x = -512;

    if (x < 0) {  // (1)

        var tmp = -x;

        ...

    }

    console.log(tmp);  // 512

}

我们可以看到变量tmp不限于从第(1)行开始的块。它存在直到函数结束。

变量被吊起

每个变量声明都是悬挂的:该声明将移至该函数的开头,但保留的赋值将保留。例如,请考虑以下函数中第(1)行中的变量声明:

function foo() {

    console.log(tmp); // undefined

    if (false) {

        var tmp = 3;  // (1)

    }

}

在内部,前面的函数是这样执行的:

function foo() {

    var tmp;  // hoisted declaration

    console.log(tmp);

    if (false) {

        tmp = 3;  // assignment stays put

    }

}

关闭

每个功能 即使它离开了创建它的作用域,它仍然与围绕它的函数的变量保持联系。例如:

function createIncrementor(start) {

    return function () {  // (1)

        start++;

        return start;

    }

}

从第(1)行开始的函数会离开其创建时所在的上下文,但仍保持与以下版本的实时连接start:

> var inc = createIncrementor(5);

> inc()

6

> inc()

7

> inc()

8

一个封闭的功能加上其周边范围的变量的连接。因此,createIncrementor()返回的是封闭。

IIFE模式:引入新的范围

有时您想引入一个新的 变量作用域-例如,防止变量成为全局变量。在JavaScript中,您不能使用块来这样做。您必须使用一个函数。但是,存在一种以块状方式使用功能的模式。它称为IIFE(立即调用的函数表达式,发音为“ iffy”):

(function () {  // open IIFE

    var tmp = ...;  // not a global variable

}());  // close IIFE

确保完全按照显示的方式键入前面的示例(注释除外)。IIFE是定义后立即调用的函数表达式。在函数内部,存在新的作用域,以防止其tmp成为全局变量。有关IIFE的详细信息,请咨询通过IIFE引入新范围。

IIFE用例:通过关闭无意间共享

闭包保持它们与外部变量的连接,有时这不是您想要的:

var result = [];

for (var i=0; i < 5; i++) {

    result.push(function () { return i });  // (1)

}

console.log(result[1]()); // 5 (not 1)

console.log(result[3]()); // 5 (not 3)

第(1)行中返回的值始终是的当前值i,而不是创建函数时的值。循环完成后,i值为5,这就是数组中所有函数都返回该值的原因。如果希望第(1)行中的函数接收的当前值的快照,则i可以使用IIFE:

for (var i=0; i < 5; i++) {

    (function () {

        var i2 = i; // copy current i

        result.push(function () { return i2 });

    }());

}

你可能感兴趣的:(JavaScript——可变范围和关闭)