一个变量的作用域(scope)是程序源代码中定义这个变量的区域。
全局变量拥有全局作用域,在javaScript代码中任何地方都有定义的。
然而在函数内声明的变量只是在函数内部有定义,他们是局部变量,作用域也只是在局部。
在函数体内,局部变量的优先级要高于全局变量。如果在函数体内重新声明一个与局部变量重名的变量,局部变量就会覆盖全局变量的值。
var scope="全局变量";
function checkscope(){
var scope="局部变量";
function nested(){
var scope = "嵌套作用域内的局部变量";
alert(scope);//输出:嵌套作用域内的局部变量
}
nested();
alert(scope);//输出:局部变量
}
checkscope();
alert(scope);//输出:全局变量
从上面的例子中可以看出,局部变量的作用域仅仅在函数内部,出了函数体之后,局部变量就会被销毁。
在nested()函数中,虽然又声明了一个scope,但是nested()中的scope是局部变量,只是与全局变量的名字相同,并不是全局变量,所以,虽然在该函数中把scope赋值为”嵌套作用域内的局部变量”,但这仅仅是一个与全局变量名称相同的一个变量而已,并没有改变全局变量的值。
我们可以通过以下这个例子来进一步理解函数作用域的问题。
var scope="全局变量";
function checkscope(){
var scope="局部变量";
function nested(){
scope = "嵌套作用域内的局部变量";
alert(scope);//输出:嵌套作用域内的局部变量
}
nested();
alert(scope);//输出:嵌套作用域内的局部变量
}
checkscope();
alert(scope);//输出:全局变量
看到这里是不是有一些懵逼了,这和刚才不是一样的吗,为什么第二次弹框不一样了呢?
上面这部分代码中,在nested()函数中,我们并没有用var来声明scope,所以,在这里的scope的作用域就被提升了,即我们将checkscope中的scope的值重置了,所以在输出的时候输出的结果为嵌套作用域内的局部变量。
之前学习过c或java等其他编程语言的童鞋会知道,在c语言中会有块级作用域这个概念。
C语言中块级作用域是以成对的花括号来界定的,也就是说除了函数代码块外,if、for等结构也属于块级作用域。
下面这个例子可以帮助我们理解一下:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
在c或c++、java中,变量的作用域是由成对的花括号来界定的,比如if中的x,在if中,x的值为2。但是,当程序运行出了if花括号以后,if中的变量x的作用域就结束了,并不会对if以外的x造成影响。但是这在js中是不一样的~
弄明白了变量的作用域之后再来考虑变量提升就简单多了。
在Javascript中,函数及变量的声明都将被提升到函数的最顶部。
在js中,变量的声明会被解析器悄悄的提升到方法体的最顶部,但是需要注意的是,提升的仅仅是变量的声明,变量的赋值并不会被提升。
function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo() {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}
其实上面两段代码是一模一样的。
变量的声明会被提升,赋值不会被提前。我们需要注意的是,函数的声明与变量的声明是不一样的。函数的函数体也会被一起提升。但是,函数的声明我们可以用两种方法。
function test() {
var test1 = function () { // 变量指向函数表达式
alert("this is test1!");
}
function test2() { // 函数声明 函数名为test2
alert("this is test2!");
}
}
test();
在上面这个例子中,对于test1来说,是声明了一个变量,这个变量指向这个函数表达式,所以解析是会将var test1 提升,而后面对变量的赋值不会被提升。对于test2,解析是会把整个函数体一起提升。所以如果我们在函数体的开始运行两个函数,test1报错TypeError “test1 is not a function” ,test2则会弹出this is test2!。
我们可以用这个例子加深一下理解。
<script language="javascript" type="text/javascript">
//在全局对象中声明两个全局函数,反模式
function foo()
{
alert("global foo");
}
function bar()
{
alert("global bar");
}
//定义全局变量
var v = "global var";
function hoistMe()
{
alert(typeof foo); //function
alert(typeof bar); //undefined
alert(v); //undefined
//为什么bar函数和变量v是未定义而不是全局变量中定义的相应的函数变量呢?
//因为函数里面定义了同名的函数和变量,无论在函数的任何位置定义这些函数和
//和变量,它们都将被提升到函数的最顶部。
foo(); //local foo
bar(); //报错,TypeError "bar is not a function"
//函数声明,变量foo以及其实现被提升到hoistMe函数顶部
function foo()
{
alert("local foo");
}
//函数表达式,仅变量bar被提升到函数顶部,实现没有被提升
var bar = function()
{
alert("local bar");
};
//定义局部变量
var v = "local";
}
(function()
{
hoistMe();
})();
//函数表达式和变量表达式只是其声明被提升,函数声明是函数的声明和实现都被提升。
/**由于函数提升的效果,hoistMe方法相当于
function hoistMe()
{
//函数声明,变量foo以及其实现被提升到hoistMe函数顶部
function foo()
{
alert("local foo");
}
//函数表达式,仅变量bar被提升到函数顶部,实现没有被提升(同变量提升)
var bar = undefined;
//变量声明被提升
var v = undefined;
alert(typeof foo); //function
alert(typeof bar); //undefined
foo(); //local foo
bar(); //报错,缺少对象
bar = function()
{
alert("local bar");
};
v = "local";
}
*/
</script>