日期:2014-05-16  浏览次数:20525 次

javascript变量的作用域--ExtJS scope必备法宝

定义

?

作用域scope

1.(名词)某样事物执行、操作、拥有控制权的那么一个区域 [1]

2. (名词) 编写程序时,程序之中变量的可见度;例如,一个函数能否使用另外一个函数所创建的变量。[2]

?

可是这能够说明什么问题呢? 每当有人在说“这是作用域的问题”或“作用域搞错了”的时候,那就是说某个函数运行起来的时候,找不到正确变量的位置。这样我们便知道应该从哪一方面入手,查找出问题所在。

?

? 正式开始

?

实际上每一个你定义的函数都是某个对象的方法。甚至是这样的写法:

?

function fn() {

? ? alert(11);

}

老兄你不是故弄玄虚吧~。做一个这样的演示可真得是简单得要命。没错!本例不需要任何Javascript文件,服务器或html。你只要打开 firefox,弹出firebug,点击console tab。在Firefox状态栏上面看到有>>>提示的地方就可以输入了。

?

输入:

?

function fn() { alert(11); };

然后回车。一切安然...你刚才做的实际上是定义了一个函数fn。接着试试:

?

fn();

然后回车。得到11的警告窗口?还不错吧?接着试试:

?

window.fn();

this.fn();

得到一样的结果吧?这是因为函数fn是window对象的一个方法,在第二行的"this"的作用域实际指向了window对象。不过多数情况中你不需要像这样window.myFunction(...)地调用函数,这样太麻烦了,程序员工作起来会很不方便。

?

? window对象

?

window 对象总是存在的,你可理解其为一个浏览器窗口对象。它包含了其它所有的对象如document 和所有的全局变量。

?

你可以打开Firebug,切换到 Script 页面并在Firebug右侧的New watch expression... 里面输入 window。观察window对象究竟有什么在里面。

?

接着,尝试找出我们之前定义过的fn函数。

?

另外,每个frame或iframe拥有其自身的window对象,其自身的全局空间。

?

? 理解作用域

?

接下的内容开始有点复杂了。切换到Firebug Console标签页然后输入:

?

var o1 = {testvar:22, fun:function() { alert('o1: ' + this.testvar); }};

var o2 = {testvar:33, fun:function() { alert('o2: ' + this.testvar); }};

结果是什么?你声明了o1 和 o2两个对象,分别都有一些属性和方法,但值不同。

?

?

接着试试:

?

fun();

window.fun();

this.fun();

出错了,是吧?因为window对象(等价于this)并没有fun的方法。试一试下面的:

?

o1.fun();

o2.fun();

22和33出来了?非常好!

?

接下来这部分的内容最复杂啦。基于这个原始的函数,如果对象的数量多的话,你必须为每个对象加上这个函数-明显是重复劳动了。这样说吧,o1.fun写得非常清晰的而且为了搞掂它已经占用了我一个星期的开发时间。想象一下代码到处散布着this变量,怎么能不头疼?如果要将调用(执行)的o1.fun方法但this会执行o2,应该怎么实现呢?试一试下面的:

?

o1.fun.call(o2);

明白了吗?当执行o1的fun方法时你强行将变量this指向到o2这个对象,换句话说,更加严谨地说:o1.fun的方法在对象o2的作用域下运行。

?

当运行一个函数,一个对象的方法时,你可将作用域当作this值的变量。

?

? 变量的可见度

?

变量的可见度和作用域的关系非常密切。我们已经了解到,可在任何对象的外部,声明变量,或在全局的函数(函数也是变量的一种)也可以,更严格说,它们是全局对象window的属性。 全局变量在任何地方都可见;无论函数的内部还是外部。如果你在某一个函数内修改了一个全局变量,其它函数也会得知这个值是修改过的。

?

对象可以有它自己的属性(像上面的testvar),这些属性允许从内部或是外部均是可见的。试:

?

alert(o1.testvar); // 从外部访问o1的属性testvar

从内部访问的演示可在两个测试对象的fun方法找到。

?

用关键字var在内部声明,相当于声明局部变量(局部声明也是在一条链上,即Scope Chain 作用域链上,Frank注):

?

i = 44;?

function fn2() {?

? ? var i = 55;?

? ? alert(i);?

}

fn2();

将得到什么?对了,55。声明在函数fn2的变量i是一个本地变量(局部变量),和等于44的全局变量i 44没什么关系。 But:

?

alert(i);

这会访问全局变量i,显示44。

?

希望本文能帮助读者彻底理解作用域变量可见性的含义。

?

嵌套的函数(作用域链)

?

当你进行函数的嵌套时,要注意实际上作用域链是发生变化的,这点可能看起来不太直观。你可把下面的代码置入firebug监视值的变化。

?

var testvar = 'window属性';

var o1 = {testvar:'1', fun:function(){alert('o1: '+this.testvar+'<<');}};

var o2 = {testvar:'2', fun:function(){alert('o2: '+this.testvar);}};

o1.fun();'1'

o2.fun();'2'

o1.fun.call(o2);'2'

这是本文的首个例子。

?

var testvar = 'window属性';

var o3 = {

? ?testvar:'3',

? ?testvar2:'3**',

? ?fun:function(){

? ? ? alert('o3: '+this.testvar);//'obj3'

? ? ? var inner = function(){

? ? ? ? ?alert('o3-inner: '+this.testvar);//'window属性'

? ? ? ? ?alert('o3-inner: '+this.testvar2);//undefined(未定义)

? ? ? };

? ? ? inner();

? ?}

};

o3.fun();

这里我们换了别的函数,这个函数与原先的函数几乎相似但区别是内部函数的写法。要注意的是内部函数运行时所在的作用域,和外部函数的作用域是不一样的。Ext可让你调用函数时指定函数的作用域,避免作用域的问题。

?

? 变量的声明

?

初始化变量时一定要加上“var”关键字,没有的话这就是一个全局变量。譬如,在下面的例子中,会有一个变量写在函数内部,然而你打算仅仅是声明局 部的变量,但实际也可能出现覆盖全局变量的值的情形。在FIREBUG "DOM"的标签页中,你可通过检测“window”看到所有的全局变量。如果你发现有“k”或“x”变量那证明你把这个变量分配在一个不合适的作用域里 面。见下例:

?

var i = 4;

var j = 5;

var