java基础:javascript面向对象的支持(2)
2008-03-14 02:19
639 查看
2. javascript面向对象的支持
--------
在前面的例子中其实已经讲到了object类型的“类型声明”与“实例创建”。在javascript中,我们需要通过一个函数来声明自己的object类型:
//---------------------------------------------------------
// javascript中对象的类型声明的形式代码
// (以后的文档中,“对象名”通常用myobject来替代)
//---------------------------------------------------------
function 对象名(参数表) {
this.属性 = 初始值;
this.方法 = function(方法参数表) {
// 方法实现代码
}
}
然后,我们可以通过这样的代码来创建这个对象类型的一个实例:
//---------------------------------------------------------
// 创建实例的形式代码
// (以后的文档中,“实例变量名”通常用obj来替代)
//---------------------------------------------------------
var 实例变量名 = new 对象名(参数表);
接下来我们来看“对象”在javascript中的一些具体实现和奇怪特性。
1). 函数在javascript的面向对象机制中的五重身份
------
“对象名”??如myobject()??这个函数充当了以下语言角色:
(1) 普通函数
(2) 类型声明
(3) 类型的实现
(4) 类引用
(5) 对象的构造函数
一些程序员(例如delphi程序员)习惯于类型声明与实现分开。例如在delphi中,interface节用于声明类型或者变量,而implementation节用于书写类型的实现代码,或者一些用于执行的函数、代码流程。
但在javascript中,类型的声明与实现是混在一起的。一个对象的类型(类)通过函数来声明,this.xxxx表明了该对象可具有的属性或者方法。
这个函数的同时也是“类引用”。在javascript,如果你需要识别一个对象的具体型别,你需要执有一个“类引用”。??当然,也就是这个函数的名字。instanceof 运算符就用于识别实例的类型,我们来看一下它的应用:
//---------------------------------------------------------
// javascript中对象的类型识别
// 语法: 对象实例 instanceof 类引用
//---------------------------------------------------------
function myobject() {
this.data = 'test data';
}
// 这里myobject()作为构造函数使用
var obj = new myobject();
var arr = new array();
// 这里myobject作为类引用使用
document.writeln(obj instanceof myobject);
document.writeln(arr instanceof myobject);
2). 反射机制在javascript中的实现
------
javascript中通过for..in语法来实现了反射机制。但是javascript中并不明确区分“属性”与“方法”,以及“事件”。因此,对属性的类型考查在js中是个问题。下面的代码简单示例for..in的使用与属性识别:
//---------------------------------------------------------
// javascript中for..in的使用和属性识别
//---------------------------------------------------------
var _r_event = _r_event = /^[oo]n.*/;
var colorsetting = {
method: 'red',
event: 'blue',
property: ''
}
var obj2 = {
a_method : function() {},
a_property: 1,
onclick: undefined
}
function propertykind(obj, p) {
return (_r_event.test(p) && (obj[p]==undefined || typeof(obj[p])=='function')) ? 'event'
: (typeof(obj[p])=='function') ? 'method'
: 'property';
}
var objectarr = ['window', 'obj2'];
for (var i=0; i');
var obj = eval(objectarr[i]);
for (var p in obj) {
var kind = propertykind(obj, p);
document.writeln('obj.', p, ' is a ', kind.fontcolor(colorsetting[kind]), ': ', obj[p], '
');
}
document.writeln('
');
}
一个常常被开发者忽略的事实是:javascript本身是没有事件(event)系统的。通常我们在javascript用到的onclick等事件,其实是ie的dom模型提供的。从更内核的角度上讲:ie通过com的接口属性公布了一组事件接口给dom。
有两个原因,使得在js中不能很好的识别“一个属性是不是事件”:
- com接口中本身只有方法,属性与事件,都是通过一组get/set方法来公布的。
- javascript中,本身并没有独立的“事件”机制。
因此我们看到event的识别方法,是检测属性名是否是以'on'字符串开头(以'on'开头的是qomo的约定)。接下来,由于dom对象中的事件是可以不指定处理函数的,这种情况下事件句柄为null值(qomo采用相同的约定);在另外的一些情况下,用户可能象obj2这样,定义一个值为 undefined的事件。因此“事件”的判定条件被处理成一个复杂的表达式: ("属性以on/on开头" && ("值为null/undefined" || "类型为function"))
另外,从上面的这段代码的运行结果来看。对dom对象使用for..in,是不能列举出对象方法来的。
最后说明一点。事实上,在很多语言的实现中,“事件”都不是“面向对象”的语言特性,而是由具体的编程模型来提供的。例如delphi中的事件驱动机制,是由win32操作系统中的窗口消息机制来提供,或者由用户代码在component/class中主动调用事件处理函数来实现。
“事件”是一个“如何驱动编程模型”的机制/问题,而不是语言本身的问题。然而以pme(property/method/event)为框架的oop概念,已经深入人心,所以当编程语言或系统表现出这些特性来的时候,就已经没人关心“event究竟是谁实现”的了。
3). this与with关键字的使用
------
在javascript的对象系统中,this关键字用在两种地方:
- 在构造器函数中,指代新创建的对象实例
- 在对象的方法被调用时,指代调用该方法的对象实例
如果一个函数被作为普通函数(而不是对象方法)调用,那么在函数中的this关键字将指向window对象。与此相同的,如果this关键字不在任何函数中,那么他也指向window对象。
由于在javascript中不明确区分函数与方法。因此有些代码看起来很奇怪:
//---------------------------------------------------------
// 函数的几种可能调用形式
//---------------------------------------------------------
function foo() {
// 下面的this指代调用该方法的对象实例
if (this===window) {
document.write('call a function.', '
');
}
else {
document.write('call a method, by object: ', this.name, '
');
}
}
function myobject(name) {
// 下面的this指代new关键字新创建实例
this.name = name;
this.foo = foo;
}
var obj1 = new myobject('obj1');
var obj2 = new myobject('obj2');
// 测试1: 作为函数调用
foo();
// 测试2: 作为对象方法的调用
obj1.foo();
obj2.foo();
// 测试3: 将函数作为“指定对象的”方法调用
foo.call(obj1);
foo.apply(obj2);
在上面的代码里,obj1/obj2对foo()的调用是很普通的调用方法。??也就是在构造器上,将一个函数指定为对象的方法。
而测试3中的call()与apply()就比较特殊。
在这个测试中,foo()仍然作为普通函数来调用,只是javascript的语言特性允许在call()/apply()时,传入一个对象实例来指定foo()的上下文环境中所出现的this关键字的引用。??需要注意的是,此时的foo()仍旧是一个普通函数调用,而不是对象方法调用。
与this“指示调用该方法的对象实例”有些类同的,with()语法也用于限定“在一段代码片段中默认使用对象实例”。??如果不使用with()语法,那么这段代码将受到更外层with()语句的影响;如果没有更外层的with(),那么这段代码的“默认使用的对象实例”将是window。
然而需要注意的是this与with关键字不是互为影响的。如下面的代码:
//---------------------------------------------------------
// 测试: this与with关键字不是互为影响的
//---------------------------------------------------------
function test() {
with (obj2) {
this.value = 8;
}
}
var obj2 = new object();
obj2.value = 10;
test();
document.writeln('obj2.value: ', obj2.value, '
');
document.writeln('window.value: ', window.value, '
');
你不能指望这样的代码在调用结束后,会使obj2.value属性置值为8。这几行代码的结果是:window对象多了一个value属性,并且值为8。
with(obj){...}这个语法,只能限定对obj的既有属性的读取,而不能主动的声明它。一旦with()里的对象没有指定的属性,或者with()限定了一个不是对象的数据,那么结果会产生一个异常。
4). 使用in关键字的运算
------
除了用for..in来反射对象的成员信息之外,javascript中也允许直接用in关键字去检测对象是否有指定名字的属性。
in关键字经常被提及的原因并不是它检测属性是否存在的能力,因此在早期的代码中,很多可喜欢用“if (!obj.propname) {}” 这样的方式来检测propname是否是有效的属性。??很多时候,检测有效性比检测“是否存有该属性”更有实用性。因此这种情况下,in只是一个可选的、官方的方案。
in关键字的重要应用是高速字符串检索。尤其是在只需要判定“字符串是否存在”的情况下。例如10万个字符串,如果存储在数组中,那么检索效率将会极差。
//---------------------------------------------------------
// 使用对象来检索
//---------------------------------------------------------
function arraytoobject(arr) {
for (var obj=new object(), i=0, imax=arr.length; i(责任编辑:包春林)
--------
在前面的例子中其实已经讲到了object类型的“类型声明”与“实例创建”。在javascript中,我们需要通过一个函数来声明自己的object类型:
//---------------------------------------------------------
// javascript中对象的类型声明的形式代码
// (以后的文档中,“对象名”通常用myobject来替代)
//---------------------------------------------------------
function 对象名(参数表) {
this.属性 = 初始值;
this.方法 = function(方法参数表) {
// 方法实现代码
}
}
然后,我们可以通过这样的代码来创建这个对象类型的一个实例:
//---------------------------------------------------------
// 创建实例的形式代码
// (以后的文档中,“实例变量名”通常用obj来替代)
//---------------------------------------------------------
var 实例变量名 = new 对象名(参数表);
接下来我们来看“对象”在javascript中的一些具体实现和奇怪特性。
1). 函数在javascript的面向对象机制中的五重身份
------
“对象名”??如myobject()??这个函数充当了以下语言角色:
(1) 普通函数
(2) 类型声明
(3) 类型的实现
(4) 类引用
(5) 对象的构造函数
一些程序员(例如delphi程序员)习惯于类型声明与实现分开。例如在delphi中,interface节用于声明类型或者变量,而implementation节用于书写类型的实现代码,或者一些用于执行的函数、代码流程。
但在javascript中,类型的声明与实现是混在一起的。一个对象的类型(类)通过函数来声明,this.xxxx表明了该对象可具有的属性或者方法。
这个函数的同时也是“类引用”。在javascript,如果你需要识别一个对象的具体型别,你需要执有一个“类引用”。??当然,也就是这个函数的名字。instanceof 运算符就用于识别实例的类型,我们来看一下它的应用:
//---------------------------------------------------------
// javascript中对象的类型识别
// 语法: 对象实例 instanceof 类引用
//---------------------------------------------------------
function myobject() {
this.data = 'test data';
}
// 这里myobject()作为构造函数使用
var obj = new myobject();
var arr = new array();
// 这里myobject作为类引用使用
document.writeln(obj instanceof myobject);
document.writeln(arr instanceof myobject);
2). 反射机制在javascript中的实现
------
javascript中通过for..in语法来实现了反射机制。但是javascript中并不明确区分“属性”与“方法”,以及“事件”。因此,对属性的类型考查在js中是个问题。下面的代码简单示例for..in的使用与属性识别:
//---------------------------------------------------------
// javascript中for..in的使用和属性识别
//---------------------------------------------------------
var _r_event = _r_event = /^[oo]n.*/;
var colorsetting = {
method: 'red',
event: 'blue',
property: ''
}
var obj2 = {
a_method : function() {},
a_property: 1,
onclick: undefined
}
function propertykind(obj, p) {
return (_r_event.test(p) && (obj[p]==undefined || typeof(obj[p])=='function')) ? 'event'
: (typeof(obj[p])=='function') ? 'method'
: 'property';
}
var objectarr = ['window', 'obj2'];
for (var i=0; i');
var obj = eval(objectarr[i]);
for (var p in obj) {
var kind = propertykind(obj, p);
document.writeln('obj.', p, ' is a ', kind.fontcolor(colorsetting[kind]), ': ', obj[p], '
');
}
document.writeln('
');
}
一个常常被开发者忽略的事实是:javascript本身是没有事件(event)系统的。通常我们在javascript用到的onclick等事件,其实是ie的dom模型提供的。从更内核的角度上讲:ie通过com的接口属性公布了一组事件接口给dom。
有两个原因,使得在js中不能很好的识别“一个属性是不是事件”:
- com接口中本身只有方法,属性与事件,都是通过一组get/set方法来公布的。
- javascript中,本身并没有独立的“事件”机制。
因此我们看到event的识别方法,是检测属性名是否是以'on'字符串开头(以'on'开头的是qomo的约定)。接下来,由于dom对象中的事件是可以不指定处理函数的,这种情况下事件句柄为null值(qomo采用相同的约定);在另外的一些情况下,用户可能象obj2这样,定义一个值为 undefined的事件。因此“事件”的判定条件被处理成一个复杂的表达式: ("属性以on/on开头" && ("值为null/undefined" || "类型为function"))
另外,从上面的这段代码的运行结果来看。对dom对象使用for..in,是不能列举出对象方法来的。
最后说明一点。事实上,在很多语言的实现中,“事件”都不是“面向对象”的语言特性,而是由具体的编程模型来提供的。例如delphi中的事件驱动机制,是由win32操作系统中的窗口消息机制来提供,或者由用户代码在component/class中主动调用事件处理函数来实现。
“事件”是一个“如何驱动编程模型”的机制/问题,而不是语言本身的问题。然而以pme(property/method/event)为框架的oop概念,已经深入人心,所以当编程语言或系统表现出这些特性来的时候,就已经没人关心“event究竟是谁实现”的了。
3). this与with关键字的使用
------
在javascript的对象系统中,this关键字用在两种地方:
- 在构造器函数中,指代新创建的对象实例
- 在对象的方法被调用时,指代调用该方法的对象实例
如果一个函数被作为普通函数(而不是对象方法)调用,那么在函数中的this关键字将指向window对象。与此相同的,如果this关键字不在任何函数中,那么他也指向window对象。
由于在javascript中不明确区分函数与方法。因此有些代码看起来很奇怪:
//---------------------------------------------------------
// 函数的几种可能调用形式
//---------------------------------------------------------
function foo() {
// 下面的this指代调用该方法的对象实例
if (this===window) {
document.write('call a function.', '
');
}
else {
document.write('call a method, by object: ', this.name, '
');
}
}
function myobject(name) {
// 下面的this指代new关键字新创建实例
this.name = name;
this.foo = foo;
}
var obj1 = new myobject('obj1');
var obj2 = new myobject('obj2');
// 测试1: 作为函数调用
foo();
// 测试2: 作为对象方法的调用
obj1.foo();
obj2.foo();
// 测试3: 将函数作为“指定对象的”方法调用
foo.call(obj1);
foo.apply(obj2);
在上面的代码里,obj1/obj2对foo()的调用是很普通的调用方法。??也就是在构造器上,将一个函数指定为对象的方法。
而测试3中的call()与apply()就比较特殊。
在这个测试中,foo()仍然作为普通函数来调用,只是javascript的语言特性允许在call()/apply()时,传入一个对象实例来指定foo()的上下文环境中所出现的this关键字的引用。??需要注意的是,此时的foo()仍旧是一个普通函数调用,而不是对象方法调用。
与this“指示调用该方法的对象实例”有些类同的,with()语法也用于限定“在一段代码片段中默认使用对象实例”。??如果不使用with()语法,那么这段代码将受到更外层with()语句的影响;如果没有更外层的with(),那么这段代码的“默认使用的对象实例”将是window。
然而需要注意的是this与with关键字不是互为影响的。如下面的代码:
//---------------------------------------------------------
// 测试: this与with关键字不是互为影响的
//---------------------------------------------------------
function test() {
with (obj2) {
this.value = 8;
}
}
var obj2 = new object();
obj2.value = 10;
test();
document.writeln('obj2.value: ', obj2.value, '
');
document.writeln('window.value: ', window.value, '
');
你不能指望这样的代码在调用结束后,会使obj2.value属性置值为8。这几行代码的结果是:window对象多了一个value属性,并且值为8。
with(obj){...}这个语法,只能限定对obj的既有属性的读取,而不能主动的声明它。一旦with()里的对象没有指定的属性,或者with()限定了一个不是对象的数据,那么结果会产生一个异常。
4). 使用in关键字的运算
------
除了用for..in来反射对象的成员信息之外,javascript中也允许直接用in关键字去检测对象是否有指定名字的属性。
in关键字经常被提及的原因并不是它检测属性是否存在的能力,因此在早期的代码中,很多可喜欢用“if (!obj.propname) {}” 这样的方式来检测propname是否是有效的属性。??很多时候,检测有效性比检测“是否存有该属性”更有实用性。因此这种情况下,in只是一个可选的、官方的方案。
in关键字的重要应用是高速字符串检索。尤其是在只需要判定“字符串是否存在”的情况下。例如10万个字符串,如果存储在数组中,那么检索效率将会极差。
//---------------------------------------------------------
// 使用对象来检索
//---------------------------------------------------------
function arraytoobject(arr) {
for (var obj=new object(), i=0, imax=arr.length; i(责任编辑:包春林)
相关文章推荐
- java基础:javascript面向对象的支持(1)
- java基础:javascript面向对象的支持(2)
- java基础:javascript面向对象的支持(1)
- java基础:javascript面向对象的支持(2)
- java基础:javascript面向对象的支持(1)
- JAVA基础:JavaScript面向对象的支持(1)
- JAVA基础:JavaScript面向对象的支持(2)
- java基础:javascript面向对象的支持(2)
- java基础:javascript面向对象的支持(1)
- JavaScript中支持面向对象的基础
- JavaScript中支持面向对象的基础
- JavaScript 中支持面向对象的基础
- JavaScript中支持面向对象的基础
- {js}JavaScript中支持面向对象的基础
- JavaScript中支持面向对象的基础
- java基础--面向对象4
- Java基础:第二十三讲 面向对象概述
- java基础整理八(面向对象4)
- 零基础学习JAVA.第七天:面向对象
- JavaScript面向对象的支持(5)