[读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中也有了~
前一段时间写一个查询条件控件客户端时曾和同事讨论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中也有了~
相关文章推荐
- javascript中的this使用(很简单的例子说明了)
- (funciton(){})() 的意义 =====JS函数和对象的意义 ========深入认识JavaScript中的this指针
- 深入理解Javascript之this关键字
- javaScript 的 this指针使用要注意(转)
- JavaScript中几个重要的属性(this、constructor、prototype)介绍
- 简单对比分析JavaScript中的apply,call与this的使用
- prototype.js 让你更深入的了解javascript的面向对象特性
- JavaScript中使用Object.prototype.toString判断是否为数组
- JavaScript使用prototype定义对象类型(转)[
- javascript 使用prototype 实现OOP继承
- prototype.js 让你更深入的了解javascript的面向对象特性
- 深入理解javascript原型和闭包(3)——prototype原型
- JQuery_JavaScript___constructor 和prototype深入分析
- JavaScript中的prototype使用说明
- 深入理解Javascript之this关键字
- 深入理解javascript之this
- JavaScript中的this使用详解
- JavaScript:prototype属性使用说明【转】
- javascript的this与prototype的区别
- 深入分析JavaScript中this指向