JAVA & XML & JAVASCRIPT & AJAX & CSS

          Web 2.0 技術(shù)儲備............

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            77 隨筆 :: 17 文章 :: 116 評論 :: 0 Trackbacks

          轉(zhuǎn)自 : http://www.bjcan.com/hengxing/readlou.asp?id=1162

          ?2). 反射機制在JavaScript中的實現(xiàn)
          ?------
          ? JavaScript中通過for..in語法來實現(xiàn)了反射機制。但是JavaScript中并不
          明確區(qū)分“屬性”與“方法”,以及“事件”。因此,對屬性的類型考查在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>);
          }

          一個常常被開發(fā)者忽略的事實是:JavaScript本身是沒有事件(Event)系統(tǒng)的。通
          常我們在JavaScript用到的onclick等事件,其實是IE的DOM模型提供的。從更內(nèi)核
          的角度上講:IE通過COM的接口屬性公布了一組事件接口給DOM。

          有兩個原因,使得在JS中不能很好的識別“一個屬性是不是事件”:
          ? - COM接口中本身只有方法,屬性與事件,都是通過一組get/set方法來公布的。
          ? - JavaScript中,本身并沒有獨立的“事件”機制。

          因此我們看到event的識別方法,是檢測屬性名是否是以'on'字符串開頭(以'On'開
          頭的是Qomo的約定)。接下來,由于DOM對象中的事件是可以不指定處理函數(shù)的,這
          種情況下事件句柄為null值(Qomo采用相同的約定);在另外的一些情況下,用戶可
          能象obj2這樣,定義一個值為 undefined的事件。因此“事件”的判定條件被處理
          成一個復(fù)雜的表達式:
          ?? ("屬性以on/On開頭" && ("值為null/undefined" || "類型為function"))

          另外,從上面的這段代碼的運行結(jié)果來看。對DOM對象使用for..in,是不能列舉出
          對象方法來的。

          最后說明一點。事實上,在很多語言的實現(xiàn)中,“事件”都不是“面向?qū)ο蟆钡恼Z
          言特性,而是由具體的編程模型來提供的。例如Delphi中的事件驅(qū)動機制,是由Win32
          操作系統(tǒng)中的窗口消息機制來提供,或者由用戶代碼在Component/Class中主動調(diào)用
          事件處理函數(shù)來實現(xiàn)。

          “事件”是一個“如何驅(qū)動編程模型”的機制/問題,而不是語言本身的問題。然
          而以PME(property/method/event)為框架的OOP概念,已經(jīng)深入人心,所以當編程語
          言或系統(tǒng)表現(xiàn)出這些特性來的時候,就已經(jīng)沒人關(guān)心“event究竟是誰實現(xiàn)”的了。


          ?3). this與with關(guān)鍵字的使用
          ?------
          ?在JavaScript的對象系統(tǒng)中,this關(guān)鍵字用在兩種地方:
          ?? - 在構(gòu)造器函數(shù)中,指代新創(chuàng)建的對象實例
          ?? - 在對象的方法被調(diào)用時,指代調(diào)用該方法的對象實例

          ?如果一個函數(shù)被作為普通函數(shù)(而不是對象方法)調(diào)用,那么在函數(shù)中的this關(guān)鍵字
          將指向window對象。與此相同的,如果this關(guān)鍵字不在任何函數(shù)中,那么他也指向
          window對象。

          ?由于在JavaScript中不明確區(qū)分函數(shù)與方法。因此有些代碼看起來很奇怪:
          //---------------------------------------------------------
          // 函數(shù)的幾種可能調(diào)用形式
          //---------------------------------------------------------
          function foo() {
          ? // 下面的this指代調(diào)用該方法的對象實例
          ? 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關(guān)鍵字新創(chuàng)建實例
          ? this.name = name;
          ? this.foo = foo;
          }

          var obj1 = new MyObject('obj1');
          var obj2 = new MyObject('obj2');

          // 測試1: 作為函數(shù)調(diào)用
          foo();

          // 測試2: 作為對象方法的調(diào)用
          obj1.foo();
          obj2.foo();

          // 測試3: 將函數(shù)作為“指定對象的”方法調(diào)用
          foo.call(obj1);
          foo.apply(obj2);

          在上面的代碼里,obj1/obj2對foo()的調(diào)用是很普通的調(diào)用方法。——也就
          是在構(gòu)造器上,將一個函數(shù)指定為對象的方法。

          而測試3中的call()與apply()就比較特殊。

          在這個測試中,foo()仍然作為普通函數(shù)來調(diào)用,只是JavaScript的語言特性
          允許在call()/apply()時,傳入一個對象實例來指定foo()的上下文環(huán)境中所
          出現(xiàn)的this關(guān)鍵字的引用。——需要注意的是,此時的foo()仍舊是一個普通
          函數(shù)調(diào)用,而不是對象方法調(diào)用。

          與this“指示調(diào)用該方法的對象實例”有些類同的,with()語法也用于限定
          “在一段代碼片段中默認使用對象實例”。——如果不使用with()語法,那
          么這段代碼將受到更外層with()語句的影響;如果沒有更外層的with(),那
          么這段代碼的“默認使用的對象實例”將是window。

          然而需要注意的是this與with關(guān)鍵字不是互為影響的。如下面的代碼:
          //---------------------------------------------------------
          // 測試: this與with關(guān)鍵字不是互為影響的
          //---------------------------------------------------------
          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>');

          你不能指望這樣的代碼在調(diào)用結(jié)束后,會使obj2.value屬性置值為8。這幾行
          代碼的結(jié)果是:window對象多了一個value屬性,并且值為8。

          with(obj){...}這個語法,只能限定對obj的既有屬性的讀取,而不能主動的
          聲明它。一旦with()里的對象沒有指定的屬性,或者with()限定了一個不是對
          象的數(shù)據(jù),那么結(jié)果會產(chǎn)生一個異常。


          ?4). 使用in關(guān)鍵字的運算
          ?------
          ?除了用for..in來反射對象的成員信息之外,JavaScript中也允許直接用in
          關(guān)鍵字去檢測對象是否有指定名字的屬性。

          ?in關(guān)鍵字經(jīng)常被提及的原因并不是它檢測屬性是否存在的能力,因此在早期
          的代碼中,很多可喜歡用“if (!obj.propName) {}” 這樣的方式來檢測propName
          是否是有效的屬性。——很多時候,檢測有效性比檢測“是否存有該屬性”更
          有實用性。因此這種情況下,in只是一個可選的、官方的方案。

          ?in關(guān)鍵字的重要應(yīng)用是高速字符串檢索。尤其是在只需要判定“字符串是否
          存在”的情況下。例如10萬個字符串,如果存儲在數(shù)組中,那么檢索效率將會
          極差。
          //---------------------------------------------------------
          // 使用對象來檢索
          //---------------------------------------------------------
          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;
          }

          這種使用關(guān)鍵字in的方法,也存在一些限制。例如只能查找字符串,而數(shù)
          組元素可以是任意值。另外,arrayToObject()也存在一些開銷,這使得它
          不適合于頻繁變動的查找集。最后,(我想你可能已經(jīng)注意到了)使用對象
          來查找的時候并不能準確定位到查找數(shù)據(jù),而數(shù)組中可以指向結(jié)果的下標。

          posted on 2006-03-20 09:39 Web 2.0 技術(shù)資源 閱讀(359) 評論(0)  編輯  收藏 所屬分類: Javascript
          主站蜘蛛池模板: 和硕县| 耒阳市| 安顺市| 正阳县| 定州市| 乌兰浩特市| 衡水市| 祁门县| 彰武县| 祁东县| 仙居县| 宝丰县| 云霄县| 麻阳| 禄丰县| 石狮市| 竹北市| 醴陵市| 新巴尔虎右旗| 英超| 桑植县| 洛隆县| 左云县| 平邑县| 哈巴河县| 安义县| 井研县| 镇原县| 北宁市| 万安县| 沂水县| 遵义市| 井研县| 县级市| 惠水县| 中方县| 安吉县| 祁门县| 元朗区| 德格县| 蒙阴县|