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

[读prototype] 深入javascript的动态性和'this'的使用

2007-02-10 11:02 609 查看
1、 javascript的动态性动到什么程度?

前一段时间写一个查询条件控件客户端时曾和同事讨论javascript对象可不可以动态取变量的值作为其属性名,因为也只考虑对象的句点操作符,所以认为不可以,其实不然,看一下下面在js shell中的操作数据:

for(var key in obj)print(key+' : '+obj[key]+' : '+(typeof obj[key])+'\n');

id : this is my id : string

dynamic : dynamic level... : string

20 : dynamic number property... : string
func : function(){alert('this is a test');} : function

var arr=[1,'2',3,function(){alert('arr test');}];

for(var key in arr)print(key+' : '+arr[key]+' : '+(typeof arr[key])+'\n');

0 : 1 : number
1 : 2 : string
2 : 3 : number
3 : function(){alert('arr test');} : function

for(var i=0;i<arr.length;i++)print(i+' : '+arr[i]+' : '+(typeof arr[i])+'\n');
0 : 1 : number
1 : 2 : string
2 : 3 : number
3 : function(){alert('arr test');} : function
//for...in胜任遍历数组和对象,常规for循环只可遍历数组
注意到其中的for…in循环所使用的对象的[]操作符,既然可以如此obj[key]动态eval出key的值然后取对象obj的相应属性值,当然也就可以解答之前的疑问(答案应该是'可以'),看一下下面的数据(其实是参生于上面数据之前的数据):

//普通的动态性

var obj={};

obj.id = 'this is my id';

this is my id

//更高层次的动态

//此种动态主要通过[]操作符实现,当然读取时可以通过[]和.操作符

var str='dynamic';var num=20;


props(obj);

Fields: id

obj[str]='dynamic level...';

dynamic level...

obj[str]='dynamic level...';props(obj);

Fields: dynamic, id

print(obj.dynamic);

dynamic level...

print(obj['dynamic']);

dynamic level...

print(obj[dynamic]);//will error

TypeError: 'dynamic' 未定义

obj[num]='dynamic number property...';props(obj);

Fields: 20, dynamic, id

print(obj[20]);//identical to : print(obj['20']);

dynamic number property...

print(obj.20)//will error

SyntaxError: 缺少 ')'

//看出些端倪来了吧,在对象操作上[]操作符还是略强于.句点操作符的(可以胜任句点操作符所无法胜任的)


或许这才叫真正的动态吧,应该有些启发吧~~

2、深入javascript的'this'的使用

在非脚本(应该是非动态性)语言如c#或java中,'this'关键字意义很确定,只要我们在某一个对象的定义中使用了this,则在运行时此this会指向我们所定义的对象(当然我们也可以通过this调用其父类的成员),而在js中则大不相同,在对象的定义中(如其中方法的定义)的使用的this在运行时指不指向我们定义的对象要看具体情况,也就是要看方法具体运行的context,也就是方法具体运行时所依附的对象,在js中这个对象是在运行时动态指定的,并非象在c#或java中不允许动态指定方法执行所依赖的对象(应该是在定义时this的定义基本就已确定)。

Js中的this的具体确定和理解有一个重要特点,那就是obj.method这种使用方式,这种方式指定了名为method方法运行时的context(也即其依附的对象)为obj(当然如果你的obj并没有定义名为method,则需要使用js的call或apply指定其运行context为obj),推而延之,对dom节点事件的指定可以这样理解,node.onclick可以认为是node对象有一个名为onclick的方法(特殊的是当鼠标点击时会调用此方法,和c#中事件订阅、发布一个道理),既然是对象的一个方法当然也可以直接调用(不由鼠标去激发),当你单击鼠标激发此事件时相当于node.onclick()这样调用onclick方法,根据上面所言也就是为onclick方法指定了运行时的context,因此onclik方法体中的this也就指向了你所指定的这个context(就是node节点对象),像这样:

<input onclick=”alert(this);”> //input即为node或 node.onclick=function(){this…..}

同时方法在js中也是对象(就是一种引用),因此如果你仅仅是将一个方法(function)的引用传给了node.onclick,相当于这样:

Var f = function(){…}; node.onclick = f;

这样使得node.onclick和f指向同一个引用,事件激发时f的方法体中的this会指向node

理解了上述对this、function、dom事件的概述后,看一下下面几组数据就应该很容易理解了:

×

Var obj = {

I:4,

A:function(){

Node.onclick = this.B; //’this’ refer to current object obj

},

B:function(){

Alert(This.I); //’this’ refer to node :[onclick runtime]}

};

因为A方法执行在obj context下,所以其中this指向了obj,则node.onclick正确获取了obj.B方法的引用,在onclick被激发时,this.I是找不到的,很明确吧~

×
Var obj = {

I:4,

A:function(){

Node.onclick = function(){

this.B(); //’this’ refer to node :[onclick runtime]

};

},

B:function(){

Alert(This.I); //’this’ refer to current object obj

}

};

只叙述和上一个不同的地方,在A方法的执行时this确实指向了obj,但onclick那时并没有被激发,到onclick事件激发时(也就是onclick方法被调用时),”this.B();”中的this根据其context指向了node,this.B也就根本找不到了


Var obj = {

I:4,

A:function(){

Var _this = this;

Node.onclick = function(){

_this.B(); //’_this’ refer to current object obj :[runtime]

//’this’ refer to node :[onclick runtime]

};

},

B:function(){

Alert(This.I); //’this’ refer to current object obj :[runtime]

}

};

这样解决了上面的问题,应该很容易理解了吧~

√(based prototype lib)

Var obj = {

I:4,

A:function(){

Node.onclick = this.B.bind(this); //’this’ refer to current object obj

//actually return a anonymous function like solution above.

},

B:function(){

Alert(This.I); //’this’ refer to current object obj :[runtime]

}

};

这个基于prototype中解决上面问题的方法,在内部prototype的bind解决方案其实和上面解决方法类似(都是采用匿名function),prototype在匿名function中用js的apply直接指定方法执行时的context,代码如下:

Function.prototype.bind = function() {

var __method = this, args = $A(arguments), object = args.shift();

return function() {

return __method.apply(object, args.concat($A(arguments)));

}

}

好了,这一下使用javascript应该更有底气了吧,对了javascript中的一些特性如closure、匿名function,.net2.0中也有了~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: