JavaScript是一项比较奇怪的语言,变量可以重复定义,相当于没有类型。
下面的是基本类型
<script>
var a=3;
function changea()
{
alert(a);
}
alert(a);//3
var a=4;//作用域链保存的a已经修改
alert(a);//4
changea();//4
</script>
下面的Object类型,引用类型。
<script>
var a=new Object();
a.name="oldname";
var b=a;
alert(b.name);//弹出是“oldname”
var a=new Object();//作用域链保存的a已经修改
a.name="newName";
alert(b.name);//弹出是“oldname”
</script>
重复定义后,原来的变量还是继续保存在内存中,没有消失。计算机记录的是地址,不是变量名。每当编译器,搜索变量的时候,先从局部定义域,到全局定义域搜索。每当重复定义之后,作用域链就会修改,a的地址换成后来定义的。
作用域链保存的是地址,不是变量名,通过变量名,来查找地址。
上面的是关于变量的,是根据语句出现的位置,离他出现最晚一次定义的。
但是函数却和变量不一样。
<script>
function a()
{
return "oldFunction\n";
}
document.write(a());
function a()
{
return "newFunction\n";
}
document.write(a());
</script>
结果是newFunction newFunction。和语句出现位置和函数定义位置前后没有关系,只是和函数最后一次定义有关。编译器会率先读取函数声明,并使其在执行代码之前使用(可以访问);但是函数表达式,则必须等到解析器执行到所在代码行,才真正的被解析。
<script>
document.write(a());//forthFunction
function a()
{
return "firstFunction\n";
}
document.write(a());//forthFunction
var a=function()
{
return "thirdFunction\n";
}
function a()
{
return "secondFunction\n";
}
document.write(a());//thirdFunction
function a()
{
return "forthFunction\n";
}
var a=function()
{
return "fifthFunction\n";
}
document.write(a());//fifthFunction
</script>
程序开始之前,函数a(),寻找函数声明,一直到最后一个定义的函数声明,加入作用域链,其他的定义的函数声明,可以忽略了,不在起作用。前两个没有遇见函数表达式,作用域链,是最后一个定义的函数声明,好吧,就是forthFunction。
第三个a(),忽略了函数声明,但是不忽略函数表达式,这个时候,找个一个函数表达式,就把这个加入作用域链,最后一个a(),和这个也是一样的。
好,我们整理一下思路,编译器在先进入程序之前,找函数声明,把最后一个声明加入作用域链,然后在进入程序之后,就会忽略他们的声明。如果遇见函数表达式,,按照顺序,不断替换,作用域链的,函数链接地址,这个时候,把它当做变量对待就可以了。
我们然后去想一下,如果变量和函数重复了呢?函数声明和函数表达式还是不一样的。通过上面的总结,应该很容易推断出来结果。如果不知道结果,自己写个小例子测试一下