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

来源:互联网 发布:部落冲突弓箭女王数据 编辑:程序博客网 时间:2024/04/28 12:07

分析比较下面几组代码,尤其注意(4)和(5)

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

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

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

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

var i=10;//定义全局变量ifunction 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隐含thisconsole.log(this.i);//输出100console.log(k);//输出500console.log(delete i);//在IE控制台销毁全局变量成功,输出true;在IE页面中销毁失败,输出falseconsole.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支持的也不好。

0 0
原创粉丝点击