声明变量和非声明变量的影响

变量无论在何处声明,都会在代码执行前处理。用var声明的变量的作用域是它当前执行的上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。如果重新声明一个JavaScript变量,它将不会丢失其值。

将赋值给未声明变量的值在执行时将其隐式的创建为全局变量(它会成为全局对象的属性)。

声明和未声明的差异

  1. 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。

    1
    2
    3
    4
    5
    6
    7
    8
    function test() {
    a = '666';
    var b = '888';
    }

    test();
    console.log(a); // 666
    console.log(b); // Uncaught ReferenceError: b is not defined
  2. 声明变量在任何代码执行前创建,而非声明变量只有在执行前赋值操作时才会被创建。

1
2
3
4
console.log(a); // "undefined"或者""(不同浏览器实现不同)
console.log(b); // 报错: Uncaught ReferenceError: b is not defined
console.log('end'); // 永不执行
var a;
  1. 声明变量是它所在上下文环境的不可配置属性,非声明变量是可配置的(如非声明变量是可被删除的)
1
2
3
4
5
6
7
8
var a = 1;
b = 2;

delete this.a; // 在严格模式下会抛出 TypeError,其它情况下执行失败并无任何提示
delete this.b;
console.log(a);
console.log(b); // 抛出ReferenceError
// 属性b已经被删除

由于这三个差异,未能声明的变量将可能导致意想不到的结果。因此,建议始终声明变量,无论它们是在函数或者全局作用域内。而且在ES5严格模式下,分配给未声明的变量会引发错误。

变量提升

由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫做“hoisting”。“hoisting”就像是把所有的变量声明移动到函数或者全局代码的开头位置。

因此,建议始终在作用域顶部声明变量(全局代码的顶部和函数代码的顶部),这可以清楚知道哪些变量是函数作用域(本地),哪些变量在作用域链上解决。

重要的是,提升将影响变量声明,而不会影响其值的初始化。