26

在为变量赋值之前在 javascript 中声明变量时,是否有类似的最佳实践?有时出于范围的原因它是必要的,但如果范围无关紧要怎么办?

// Declare first
(function() {
    var foo = 'bar',
        a = 500,
        b = 300,
        c;

    // Some things get done here with a and b before c can use them...

    c = a * b;    

    // c is now ready to use...
    doSomething(c);
}());

// Declare when needed
(function() {
    var foo = 'bar',
        a = 500,
        b = 300;

    // Some things get done here with a and b before c can use them...

    var c = a * b; 

    // c is now ready to use...
    doSomething(c);
}());

而且我还想知道与对象文字类似的最佳实践是什么:

// Add property with null assigned to it
var myObj = {
    foo: null,

    doSomething: function() {
        this.foo = 'bar';
    }
};

// Property gets added when value is set
var myObj = {
    doSomething: function() {
        this.foo = 'bar';
    }
};
4

1 回答 1

24

这主要是风格问题。

由于var声明会自动提升到作用域的顶部,因此将它们放在其作用域的顶部是有意义的,这样您就可以更接近解释器的执行方式来阅读代码。

Crockford 建议在其范围的顶部声明变量。它确实很有意义,因为它消除了一些常见的误解。

例如:

for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 0);
}

由于var具有函数范围,所有迭代(以及其中的函数)都引用相同的i. 由于所有三个定时函数都将在循环结束后执行,因此上面的代码段记录3了 3 次。

现在对于那些有块作用域经验的人来说,上述行为并不是很清楚。重写片段:

var i;
for (i = 0; i < 3; i++) {
    // ...
}

现在,i在全局范围内声明,与前面的代码片段完全相同。但是,这一点要清楚得多。


另一个误解:

(function() {
    if (true) {
        var foo = 1;
    } else {
        var foo = 1;
    }
}());

同样,在块范围的语言中¹上面是完全有效的。但是,由于var声明在解析时被提升到当前函数范围的顶部,所以上面的内容等价于:

(function() {
    var foo;
    var foo;
    if (true) {
        foo = 1;
    } else {
        foo = 1;
    }
}());

该变量被声明了两次。大多数浏览器会忽略第二个声明,代码会“工作”,但是像JSHint这样的静态代码分析工具会对你大喊大叫。

你可以只用一个声明重写它,它是完全有效的:

(function() {
    if (true) {
        var foo = 1;
    } else {
        foo = 1;
    }
}());

但是像我这样的 OCD 类程序员会觉得它相当难看。再次声明,在范围的顶部:

(function() {
    var foo;
    if (true) {
        foo = 1;
    } else {
        foo = 1;
    }
}());

看起来整齐了许多。


同样,这主要是风格问题。就个人而言,如果我有一个巨大的函数,我讨厌一直向上滚动只是为了检查一个变量是否已经声明并将其添加到列表中。在这种情况下,我可能会在函数中间添加几个var声明(违反 Crockford 的建议),我个人认为这些声明更易于阅读和维护。

由于这是一个风格问题,只要确保您的代码尽可能地易于维护和简洁。


在硬币的另一面,我承认,就个人而言,我var在第一次使用变量时已经开始并且主要使用了声明。这是语言的一个方面,您可以毫无问题地使用它。

但我也承认,如果我从一开始就遵循 Crockford 的建议,我就会少很多麻烦(就像上面显示的误解一样),并且会更快地掌握 JavaScript 的函数作用域方面。


¹ 请注意,JS 1.7 通过 引入了块作用域变量let,但尚未得到广泛支持。

于 2013-06-04T08:57:11.547 回答