文章探索:   分类:    关键字:  
  + 栏目导航
  + 相关文章
document 对象
Window.Open详解
JS replace 方法
JScript 属性
JScript 对象
JScript 方法
关于window.opener的用法
JavaScript语法——style.display 属..
不被拦截的弹出窗口代码
showModalDialog和showModelessDialog..
showModelessDialog()使用详解
IE中非模式对话框(showModelessDialog..
JS eval()函数
Preferences 指南
JS中的setTimeout和setInterval的区别
JavaScript对象与数组参考大全
javascript动态增加、删除、填充表格..
用Java实现几种常见的排序算法
JavaScript 日期函数
JavaScript 使用字符串函数
如何用Javascript获得TextArea中的光..
Document 对象方法
在input中只能输入数字
selection.createRange() 用法例子
获取网页各种宽高的值
JavaScript方法 - indexOf方法
substring函数详解
40种网页常用小技巧(javascript)
event.X和event.clientX有什么区别
clientX, clientY,offsetX, offsetY,..


技术教程 -> JavaScript教程 ->  
JavaScript面向对象的支持(2)
来源:转载   人气:728   录入时间:2007-11-8
    Qomolangma OpenProject v0.9
   
   
   类别 :Rich Web Client
   关键词 :JS OOP,JS Framwork, Rich Web Client,RIA,Web Component,
    DOM,DTHML,CSS,JavaScript,JScript
   
   项目发起:aimingoo (aim@263.net)
   项目团队:aimingoo, leon(pfzhou@gmail.com)
   有贡献者:JingYu(zjy@cnpack.org)
   ================================================================================
   
   
    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<objectArr.length; i++) {
    document.writeln('<p>for ', objectArr[i], '<hr>');
   
    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], '<br>');
    }
   
    document.writeln('</p>');
   }
   
   一个常常被开发者忽略的事实是: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.', '<BR>');
    }
    else {
    document.write('call a method, by object: ', this.name, '<BR>');
    }
   }
   
   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, '<br>');
   document.writeln('window.value: ', window.value, '<br>');
   
   你不能指望这样的代码在调用结束后,会使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<imax; i++) {
    obj[arr[i]]=null;
    }
    return obj;
   }
   
   var
    arr = ['abc', 'def', 'ghi']; // more and more...
    obj = arrayToObject(arr);
   
   function valueInArray(v) {
    for (var i=0, imax=arr.length; i<imax; i++) {
    if (arr[i]==v) return true;
    }
   
    return false;
   }
   
   function valueInObject(v) {
    return v in obj;
   }
   
     这种使用关键字in的方法,也存在一些限制。例如只能查找字符串,而数组元素可以是任意值。另外,arrayToObject()也存在一些开销,这使得它不适合于频繁变动的查找集。最后,(我想你可能已经注意到了)使用对象来查找的时候并不能准确定位到查找数据,而数组中可以指向结果的下标。
   




Copyright(C)2007-2024 广州市佳沛数码科技有限公司 版权所有
公司地址: 广州市荔湾区东漖北路560号511室
电话:020-81803473 传真:020-81544987