javascript嵌套的函数(作用域链)
JavaScript 函数 嵌套 作用域
2023-06-13 09:14:17 时间
嵌套的函数(作用域链)
当你进行函数的嵌套时,要注意实际上作用域链是发生变化的,这点可能看起来不太直观。你可把下面的代码置入firebug监视值的变化。
复制代码代码如下:
当你进行函数的嵌套时,要注意实际上作用域链是发生变化的,这点可能看起来不太直观。你可把下面的代码置入firebug监视值的变化。
vartestvar="window属性";
varo1={testvar:"1",fun:function(){alert("o1:"+this.testvar+"<<");}};
varo2={testvar:"2",fun:function(){alert("o2:"+this.testvar);}};
o1.fun();"1"
o2.fun();"2"
o1.fun.call(o2);"2"
这是本文的首个例子。
vartestvar="window属性";
varo3={
testvar:"3",
testvar2:"3**",
fun:function(){
alert("o3:"+this.testvar);//"obj3"
varinner=function(){
alert("o3-inner:"+this.testvar);//"window属性"
alert("o3-inner:"+this.testvar2);//undefined(未定义)
};
inner();
}
};
o3.fun();
这里我们换了别的函数,这个函数与原先的函数几乎相似但区别是内部函数的写法。要注意的是内部函数运行时所在的作用域,和外部函数的作用域是不一样的。Ext可让你调用函数时指定函数的作用域,避免作用域的问题。
变量的声明
初始化变量时一定要加上“var”关键字,没有的话这就是一个全局变量。譬如,在下面的例子中,会有一个变量写在函数内部,然而你打算仅仅是声明局部的变量,但实际也可能出现覆盖全局变量的值的情形。在FIREBUG"DOM"的标签页中,你可通过检测“window”看到所有的全局变量。如果你发现有“k”或“x”变量那证明你把这个变量分配在一个不合适的作用域里面。见下例:
vari=4;
varj=5;
vark=7;
varfn=function(){
vari=6;
k=8;//注意前面没有var所以这句话的意思的把8赋予到变量k中去!
alert(i);//6
alert(j);//5
alert(k+"-1");//8-1
x=1;//这句的作用有两种情况,创建全部变量x或覆盖(overwrite)全部变量x
};
fn();
alert(k+"-2");//8-2(注意不是7-2)
与前面例子变化不大,另外注意的是函数内的k前面是没有var关键字的,所以这里不是声明局部变量,而是将某个值再次分配到k这个全局变量中。另外要注意的是,alert方法执行期间,参数i是当前能找到的局部变量,它的值是6,但参数j在当前作用域找不到,就沿着作用域链(scopechain)向上查找,一直找到全局变量的那个j为止。
在Ext中指定作用域
前面已提及,当调用函数时Ext能灵活处理作用域的问题。部分内容来自dj的帖子。
调用函数时,你可以把this想象为每个函数内的一个特殊(躲起来的)参数。无论什么时候,JavaScript都会把this放到function内部。它是基于一种非常简单的思想:如果函数直接是某个对象的成员,那么this的值就是这个对象。如果函数不是某个对象的成员那么this的值便设为某种全局对象(常见有,浏览器中的window对象)。下面的内部函数可以清晰的看出这种思想。
一个函数,若是分配到某个变量的,即不属于任何对象下的一员,那么this的参数就变为windows对象。下面是一个例子,可直接粘贴到Firebug的console:
varobj={
toString:function(){return"obj的范围内(作用域内)";},//重写toString函数,方便执行console.log(this)时的输出
func:function(){
//这里的函数直接从属与对象"object"
console.log(this);
varinnerFunc=function(){
//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
console.log(this);
};
innerFunc();
}
};
obj.func();
//输出"obj的范围内(作用域内)"
//输出"Window的一些相关内容..."
缺省下是这样调用一个参数的-但你也可以人为地改变this参数,只是语法上稍微不同。将最后一行的"obj.func();"改为:
obj.func.call(window);
//输出"Window的一些相关内容..."
//输出"Window的一些相关内容..."
从上面的例子中可以发现,call实际上是另外一个函数(方法)。call属于系统为obj.func内建的方法(根据JavaScript之特点可得知,函数是一种对象。)。
通过这样改变this指向的作用域,我们可以继续用一个例子来修正innerFunc中的this参数,——“不正确”的指向:
varobj={
toString:function(){return"obj的范围内(作用域内)";},//重写toString函数,方便执行console.log(this)时的输出
func:function(){
//这里的函数直接从属与对象"object"
console.log(this);
varinnerFunc=function(){
//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
console.log(this);
};
innerFunc.call(this);
}
};
obj.func();
//输出"obj的范围内(作用域内)"
//输出"obj的范围内(作用域内)"
Ext的作用域配置
可以看到,没有分配作用域的函数,它的this"指向的是浏览器的window对象(如事件句柄eventhandler等等),——除非我们改变this的指针。Ext的很多类中scope是一个配置项(configuration)能够进行指针的绑定。相关的例子参考Ajax.request。
Ext的createDelegate函数
*除了内建的call/apply方法,Ext还为我们提供--辅助方法createDelegate。该函数的基本功能是绑定this指针但不立刻执行。传入一个参数,createDelegate方法会保证函数是运行在这个参数的作用域中。如:
varobj={
toString:function(){return"obj的范围内(作用域内)";},//重写toString函数,方便执行console.log(this)时的输出
func:function(){
//这里的函数直接从属与对象"object"
console.log(this);
varinnerFunc=function(){
//n这里的函数不是特定对象的直接成员,只是另外一个函数的变量而已
console.log(this);
};
innerFunc=innerFunc.createDelegate(this);//这里我们用委托的函数覆盖了原函数。
innerFunc();//按照一般的写法调用函数
}
};
obj.func();
//输出"obj的范围内(作用域内)"
//输出"obj的范围内(作用域内)"
这是一个小小的例子,其原理是非常基本基础的,希望能够好好消化。尽管如此,在现实工作中,我们还是容易感到迷惑,但基本上,如果能按照上面的理论知识去分析来龙去脉,万变还是不离其中的。
另外还有一样东西,看看下面的例子:
varsDs.load({callback:function(records){
col_length=varsDs.getCount();//这里的varDs离开了作用域?
//col_length=this.getCount();//这个this等于store吗?
for(varx=0;x<col_length;x++)
{
colarray[x]=varsDs.getAt(x).get("hex");
}
}});不过可以写得更清晰:
varobj={
callback:function(records){
col_length=varsDs.getCount();//这里的varDs离开了作用域?
//col_length=this.getCount();//这个this等于store吗?
//...
}
};
varsDs.load(obj);现在函数callback直接挂在obj上,因此this指针等于obj。
但是注意:这样做没用的。为什么?因为你不知obj.callback最终执行时发生什么情形。试想一下Ext.data.Store的load方法(仿造的实现):
...
load:function(config){
varo={};
o.callback=config.callback;
//进行加载
o.callback();
}
...
这个仿造的实现中,回调函数的作用域是私有变量“o”。因为通常你无法得知函数是如何被调用的,如果不声明作用域,你很可能无法在回调函数中使用this参数。
相关文章
- javascript 基础_JavaScript高级编程
- javascript页面刷新的几种方法[通俗易懂]
- 【说站】JavaScript定义函数的两种方法
- 为什么说:JavaScript 模块中的默认导出很糟糕
- JavaScript——正则表达式
- 投巧解决JavaScript split方法出现空字符的问题
- 面试官:能用JavaScript手写一个bind函数吗1
- 「 3.JavaScript字面量与变量 」
- 26行JavaScript代码 仿async的 并行执行和序列执行函数详解编程语言
- JavaScript将首字母转成大写详解编程语言
- javascript组件封装中一段通用代码解读详解编程语言
- 21个值得收藏的Javascript技巧
- AJAX入门之深入理解JavaScript中的函数
- 使一个函数作为另外一个函数的参数来运行的javascript代码
- javascript动态加载css方法总结
- javascript十个最常用的自定义函数(中文版)
- javascript之嵌套函数使用方法
- JavaScript嵌套函数指向this对象错误的解决方法
- JavaScript动态添加脚本,并触发回调函数的实现代码
- Javascript中的函数声明与函数表达式(奇技淫巧)
- JavaScript中valueOf函数与toString方法深入理解
- JAVASCRIPT模式窗口中下载文件无法接收iframe的流
- IE与FF下javascript获取网页及窗口大小的区别详解
- javascript随机之洗牌算法深入分析
- 浅析javascript的间隔调用和延时调用
- Javascript学习笔记之函数篇(三):闭包和引用
- javascript中声明函数的方法及调用函数的返回值
- JavaScript学习笔记之JS函数
- JavaScript截取字符串的2个函数介绍
- JavaScript的arguments对象应用示例