JavaScript的变量声明
JavaScript的变量声明语句无论出现在何处,都会先于其他代码首先被执行。使用var关键词声明变量的作用域是当前的执行上下文,有可能是外围函数,或者,当变量声明在函数体之外时,则为全局变量。
向一个未声明变量赋值会隐式地将其创建为一个全局变量(它变成了全局对象的一个属性)。声明变量与未声明变量之间的区别为:
1. 声明变量的作用范围限定在其执行的上下文环境中。未声明的变量总是全局的。
function x() {
y = 1; // Throws a ReferenceError in strict mode
var z = 2;
}
x();
console.log(y); // logs "1"
console.log(z); // Throws a ReferenceError: z is not defined outside x
2. 声明变量在其他代码执行之前创建。未声明的变量在其赋值语句执行之前都是不存在的。
console.log(a); // Throws a ReferenceError.
console.log('still going...'); // Never executes.
var a;
console.log(a); // logs "undefined" or "" depending on browser.
console.log('still going...'); // logs "still going...".
3. 声明变量是执行上下文(函数或者全局)的不可配置的属性。而未声明变量是可配置的(例如,可以被delete)
var a = 1;
b = 2;
delete this.a; // Throws a TypeError in strict mode. Fails silently otherwise.
delete this.b;
console.log(a, b); // Throws a ReferenceError.
// The 'b' property was deleted and no longer exists.
由于以上三点不同,使用未声明变量可能会带来意想不到的结果。因此建议无论是全局变量还是局部变量,在使用前都要声明。在ECMAScript5的严格模式下,对未声明变量赋值会抛出一个错误。
声明提前(var hoisting):
JavaScript的函数作用域是指在函数内声明的所有变量在函数体内是始终可见的。有趣的是,这意味着变量甚至可以先使用,后声明。
JavaScript的这一特性被非正式地称为声明提前(hoiosting),即JavaScript函数中所有变量的声明都被“提前”至函数体的顶部。
(“声明提前”的操作是在JavaScript引擎的“预编译”时进行的,即在代码运行之前)
例如下面的JavaScript代码:
var scope = "global";
function f() {
alert(scope);
var scope = "local"; //覆盖全局变量
alert(scope);
}
读者可能误以为函数f的第一个alert会输出"global",因为代码此时还没有执行到var语句声明局部变量的代码行。
其实不然,由于函数作用域的特性,局部变量在整个函数体内始终是有定义的,亦即,在函数体内局部变量覆盖了同名的全局变量。尽管如此,只有程序执行到var语句时,局部变量才会被赋值。因此上述过程等价于,将函数体内的变量声明“提前”至函数体顶部,而变量的初始化保留在原处。
function f() {
var scope; //函数体顶部声明局部变量
alert(scope); //输出"undefined"
scope = "local"; //变量初始化赋值
alert(scope); //输出"local"
}
基于此原因,建议将变量的声明都放在作用域的顶部(全局代码的顶端,或者函数代码的开始),从而清楚地区分变量的作用域,哪些是函数作用域,哪些在作用域链上解析。
参考资料:
1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
2. 《JavaScript权威指南》 第6版 中文版
本文链接:http://bookshadow.com/weblog/2015/03/13/javascript-var-statement-hoisting/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。
书影网友 发布于 2017年6月21日 10:25 #
谢谢笔者,解决了我的疑惑