您的位置:首页 > Web前端 > JavaScript

JavaScript笔记(4)作用域与作用域链

2016-05-27 21:21 525 查看
分析比较下面几组代码,尤其注意(4)和(5)

注意(7)在控制台调试和页面内调试的区别

(1)全局变量贯穿所有代码

var i=10;//定义全局变量
function f(){
console.log(i);//输出全局变量i的值10
}
f();
console.log(i);//输出全局变量i的值10

(2)局部变量在函数内替换同名全局变量

var i=10;//定义全局变量i
function f(){
var i=20;//定义局部变量i
console.log(i);//输出局部变量i的值20
}
f();
console.log(i);//输出全局变量i的值10

(3)局部变量不能在函数外使用

function f(){
var i=20;//定义局部变量i
console.log(i);//输出局部变量i的值20
}
f();
console.log(i);//超出函数定义的范围,局部变量i已经不存在,输出"“i”未定义"

(4)“提前”使用局部变量,会得到undefined值

function f(){
console.log(i);//输出undefined,注意此处的i是局部的,但为undefined
var i=20;//虽然不是函数的第一句,但其作用域已然相当于第一句,但此初始化之前的输出为undefined
console.log(i);//输出已经初始化的值20
}
f();


(5)作用域以函数为界限,而不是“复合语句”

function f(){
if(true){
var m=30;//变量m在此函数内均可访问,而不是限定在此“复合语句”中
}
for(var n=1;n<10;n++);
console.log(m);//输出30
console.log(n);//输出10
}
f();

(6)函数内定义变量时不用var引导,则自动升级为全局变量

function f(){
i=100;//虽然在函数内,但没有使用var,则自动升级为全局变量
console.log(i);//输出全局变量i的值100
}
f();
console.log(i);//输出全局变量i的值100


(7)全局变量实际上是全局对象this的一个属性

var i=100;
k=300;
function f(){
var j=200;
console.log(i);//输出100
console.log(delete j);//销毁局部变量失败,输出false。(函数结束局部变量会自动销毁)
console.log(j);//输出200
}
f();
this.k=500;//k=500隐含this
console.log(this.i);//输出100
console.log(k);//输出500
console.log(delete i);//在IE控制台销毁全局变量成功,输出true;在IE页面中销毁失败,输出false
console.log(i);//在IE控制台全局变量i已经被销毁,无法引用,输出"“i”未定义" ;在IE页面中销毁失败,输出100

 (8)作用域链

观察函数嵌套定义形成的作用域链。

全局变量就是全局对象this的属性,函数内定义的变量就是本函数(对象)的属性,引用变量时如果本函数不存在该变量,则会查找父节点中的同名变量,如果父节点没有该属性(变量),则继续查找父节点的父节点,以此类推,直到全局对象。如果全局对象也没有该属性,则导致“引用出错(ReferenceError)”的异常。

var i=100;
var j=500;
function f1(){
var i=200;
console.log("f1.i=="+i);//f1()内含有局部变量i的定义,因此查找链为:f1(),输出f1.i==200
function f2(){
i=300;
console.log("f2.i=="+i);//f2()内含有i的重新赋值,因此查找链为:f2(),输出f2.i==300
function f3(){
console.log("f3.i=="+i);//f3()内虽然含有i的重新赋值,但在下一句,因此查找链为:f2()->f3(),输出f3.i==300
i=400;//如果将此句改为 var i=400,则上一句的输出为f3.i==undefined(原因参见(4))
function f4(){
console.log("f4.i=="+i);//f4()内没有i的定义,因此查找链为:f4()->f3(),输出f4.i==400
console.log("f4.this.i=="+this.i);//直接使用全局对象this的属性i的值,因此输出f4.this.i==100
function f5(){
console.log("f5.j=="+j);//f5()至f1()内均无变量j的定义,因此查找链为:f5()->f4()->f3()->f2()->f1()->window,输出f5.j==500
console.log("f5.i=="+i);//查找链为:f5()->f4()->f3(),输出f5.i==400
console.log("f5.this.i=="+this.i);//直接使用全局对象this的属性i的值,因此输出f5.this.i==100
console.log("f5.k=="+k);//查找链为:f5()->f4()->f3()->f2()->f1()->window,但直到window对象也没有k属性,因此输出SCRIPT5009: “k”未定义
}
f5();
}
f4();
}
f3();
}
f2();
}
f1();
应用中的典型错误(转自:http://blog.csdn.net/yueguanghaidao/article/details/9568071 的举例,感谢博主yueguanghaidao
<html>
<head>
<script type="text/javascript">
function buttonInit(){
for(var i=1;i<4;i++){
var b=document.getElementById("button"+i);
b.addEventListener("click",function(){ alert("Button"+i);},false);
}
}
window.onload=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

三个按钮都是弹出:"Button4"。当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,所以弹出”button4“。

注意: Internet Explorer 8 及更早IE版本不支持 addEventListener() 方法,IE9支持的也不好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 作用域