现在的位置: 首页 > 综合 > 正文

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

2011年02月27日 ⁄ 综合 ⁄ 共 3943字 ⁄ 字号 评论关闭
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]动态evalkey的值然后取对象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,则需要使用jscallapply指定其运行contextobj),推而延之,对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.onclickf指向同一个引用,事件激发时f的方法体中的this会指向node

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

× 

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指向了nodethis.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中解决上面问题的方法,在内部prototypebind解决方案其实和上面解决方法类似(都是采用匿名function),prototype在匿名function中用jsapply直接指定方法执行时的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中也有了~

【上篇】
【下篇】

抱歉!评论已关闭.