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

分析比较下面几组代码,尤其注意(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.οnlοad=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支持的也不好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值