函数作用域和声明提前
在一些编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明他们的代码之外是不可见得,我们称之为块级作用域(block scope)。
但js中没有块级作用域,取而代之的使用了函数作用域(function scope):变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
function test() {
var i = 0; // i在整个函数体内均有定义
if(true) {
var j = 0; // j在函数体内均有定义,不仅仅在if代码段
for(var k = 0; k < 10; k++) { // k在函数体内均有定义,不仅仅在循环内
}
console.log("k = " + k); // k已经定义,输出10
}
console.log("j = " + j); // j已经定义,输出0
}输出结果:
k = 10
j = 0
js的函数作用域是指在函数内声明的所有变量,在函数体内始终是可见的,这也意味着,在变量声明之前甚至已经可以使用。js的这个特性被非正式的称为声明提前(hoisting),即js函数里声明的所有对象(但不涉及赋值)都被提前至函数体的顶部。
var scopeStr = "global";
function test() {
// js函数作用域的特性,会把局部变量的定义提前,也就是局部变量覆盖了全局变量,但是赋值不提前,所以会输出undefined
console.log("scopeStr = " + scopeStr);
var scopeStr = "local";
console.log("scopeStr = " + scopeStr);
}运行结果:
scopeStr = undefined
scopeStr = local
等价于:
var scopeStr = "global";
function test() {
var scopeStr;
console.log("scopeStr = " + scopeStr);
scopeStr = "local";
console.log("scopeStr = " + scopeStr);
}运行结果:
scopeStr = undefined
scopeStr = local
在块级作用域的编程语言中,将变量声明和使用变量的代码尽肯能的靠近,通常来说是一个比较好的编码习惯。
但js不是块级作用域,因此一些人特意将变量声明放在函数体顶部,而不是靠近使用变量之处,这种代码可以使得他们的源代码非常清晰的反映出真实的变量作用域。