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

          八、JavaScript面向?qū)ο蟮闹С?br />~~~~~~~~~~~~~~~~~~
          很少有人對JavaScript的面向?qū)ο筇匦赃M(jìn)行系統(tǒng)的分析。我希望接下來的文字讓你了解到這
          個語言最少為人知的一面。


          1. JavaScript中的類型
          --------
          雖然JavaScript是一個基于對象的語言,但對象(Object)在JavaScript中不是第一型的。JS
          是以函數(shù)(Function)為第一型的語言。這樣說,不但是因為JS中的函數(shù)具有高級語言中的函
          數(shù)的各種特性,而且也因為在JS中,Object也是由函數(shù)來實現(xiàn)的。——關(guān)于這一點,可以在
          后文中“構(gòu)造與析構(gòu)”部分看到更進(jìn)一步的說明。

          JS中是弱類型的,他的內(nèi)置類型簡單而且清晰:
          ---------------------------------------------------------
          undefined : 未定義
          number??? : 數(shù)字
          boolean?? : 布爾值
          string??? : 字符串
          function? : 函數(shù)
          object??? : 對象

          ?1). undefined類型
          ========================
          在IE5及以下版本中,除了直接賦值和typeof()之外,其它任何對undefined的操作都將導(dǎo)致
          異常。如果需要知道一個變量是否是undefined,只能采用typeof()的方法:
          <script>
          var v;
          if (typeof(v) == 'undefined') {
          ? // ...
          }
          </script>

          但是在IE5.5及以上版本中,undefined是一個已實現(xiàn)的系統(tǒng)保留字。因此可以用undefined來
          比較和運算。檢測一個值是否是undefined的更簡單方法可以是:
          <script>
          var v;
          if (v === undefined) {
          ? // ...
          }
          </script>

          因此為了使得核心代碼能(部分地)兼容IE5及早期版本,Romo核心單元中有一行代碼用來
          “聲明”一個undefined值:
          //---------------------------------------------------------
          // code from Qomolangma, in JSEnhance.js
          //---------------------------------------------------------
          var undefined = void null;

          這一行代碼還有一點是需要說明的,就是void語句的應(yīng)用。void表明“執(zhí)行其后的語句,且
          忽略返回值”。因此在void之后可以出現(xiàn)能被執(zhí)行的任何“單個”語句。而執(zhí)行的結(jié)果就是
          undefined。當(dāng)然,如果你愿意,你也可以用下面的代碼之一“定義undefined”。
          //---------------------------------------------------------
          // 1. 較復(fù)雜的方法,利用一個匿名的空函數(shù)執(zhí)行的返回
          //---------------------------------------------------------
          var undefined = function(){}();

          //---------------------------------------------------------
          // 2. 代碼更簡潔,但不易懂的方法
          //---------------------------------------------------------
          var undefined = void 0;

          void也能像函數(shù)一樣使用,因此void(0)也是合法的。有些時候,一些復(fù)雜的語句可能不能
          使用void的關(guān)鍵字形式,而必須要使用void的函數(shù)形式。例如:
          //---------------------------------------------------------
          // 必須使用void()形式的復(fù)雜表達(dá)式
          //---------------------------------------------------------
          void(i=1);?????? // 或如下語句:
          void(i=1, i++);


          ?2). number類型
          ========================
          JavaScript中總是處理浮點數(shù),因此它沒有象Delphi中的MaxInt這樣的常量,反而是有這
          樣兩個常值定義:
          ? Number.MAX_VALUE? : 返回 JScript 能表達(dá)的最大的數(shù)。約等于 1.79E+308。
          ? Number.MIN_VALUE? : 返回 JScript 最接近0的數(shù)。約等于 2.22E-308。

          因為沒有整型的緣故,因此在一些關(guān)于CSS和DOM屬性的運算中,如果你期望取值為整數(shù)2,
          你可能會得到字符串“2.0”——或者類似于此的一些情況。這種情況下,你可能需要用
          到全局對象(Gobal)的parseInt()方法。

          全局對象(Gobal)中還有兩個屬性與number類型的運算有關(guān):
          ? NaN????? : 算術(shù)表達(dá)式的運算結(jié)果不是數(shù)字,則返回NaN值。
          ? Infinity : 比MAX_VALUE更大的數(shù)。

          如果一個值是NaN,那么他可以通過全局對象(Gobal)的isNaN()方法來檢測。然而兩個NaN
          值之間不是互等的。如下例:
          //---------------------------------------------------------
          // NaN的運算與檢測
          //---------------------------------------------------------
          var
          ? v1 = 10 * 'a';
          ? v2 = 10 * 'a';
          document.writeln(isNaN(v1));
          document.writeln(isNaN(v2));
          document.writeln(v1 == v2);

          全局對象(Gobal)的Infinity表示比最大的數(shù) (Number.MAX_VALUE) 更大的值。在JS中,
          它在數(shù)學(xué)運算時的價值與正無窮是一樣的。——在一些實用技巧中,它也可以用來做一
          個數(shù)組序列的邊界檢測。

          Infinity在Number對象中被定義為POSITIVE_INFINITY。此外,負(fù)無窮也在Number中被定
          義:
          ? Number.POSITIVE_INFINITY? : 比最大正數(shù)(Number.MAX_VALUE)更大的值。正無窮。
          ? Number.NEGATIVE_INFINITY? : 比最小負(fù)數(shù)(-Number.MAX_VALUE)更小的值。負(fù)無窮。

          與NaN不同的是,兩個Infinity(或-Infinity)之間是互等的。如下例:
          //---------------------------------------------------------
          // Infinity的運算與檢測
          //---------------------------------------------------------
          var
          ? v1 = Number.MAX_VALUE * 2;
          ? v2 = Number.MAX_VALUE * 3;
          document.writeln(v1);
          document.writeln(v2);
          document.writeln(v1 == v2);

          在Global中其它與number類型相關(guān)的方法有:
          ?isFinite()?? : 如果值是NaN/正無窮/負(fù)無窮,返回false,否則返回true。
          ?parseFloat() : 從字符串(的前綴部分)取一個浮點數(shù)。不成功則返回NaN。


          ?3). boolean類型
          ========================
          ?(略)

          ?4). string類型
          ========================
          JavaScript中的String類型原本沒有什么特殊的,但是JavaScript為了適應(yīng)
          “瀏覽器實現(xiàn)的超文本環(huán)境”,因此它具有一些奇怪的方法。例如:
          ? link() : 把一個有HREF屬性的超鏈接標(biāo)簽<A>放在String對象中的文本兩端。
          ? big()? : 把一對<big>標(biāo)簽放在String對象中的文本兩端。
          以下方法與此類同:
          ? anchor()
          ? blink()
          ? bold()
          ? fixed()
          ? fontcolor()
          ? fontsize()
          ? italics()
          ? small()
          ? strike()
          ? sub()
          ? sup()

          除此之外,string的主要復(fù)雜性來自于在JavaScript中無所不在的toString()
          方法。這也是JavaScript為瀏覽器環(huán)境而提供的一個很重要的方法。例如我們
          聲明一個對象,但是要用document.writeln()來輸出它,在IE中會顯示什么呢?

          下例說明這個問題:
          //---------------------------------------------------------
          // toString()的應(yīng)用
          //---------------------------------------------------------
          var
          ? s = new Object();

          s.v1 = 'hi,';
          s.v2 = 'test!';
          document.writeln(s);
          document.writeln(s.toString());

          s.toString = function() {
          ? return s.v1 + s.v2;
          }
          document.writeln(s);

          在這個例子中,我們看到,當(dāng)一個對象沒有重新聲明(覆蓋)自己toString()方
          法的時候,那么它作為字符串型態(tài)使用時(例如被writeln),就會調(diào)用Java Script
          環(huán)境缺省的toString()。反過來,你也可以重新定義JavaScript理解這個對象
          的方法。

          很多JavaScript框架,在實現(xiàn)“模板”機(jī)制的時候,就利用了這個特性。例如
          他們用這樣定義一個FontElement對象:
          //---------------------------------------------------------
          // 利用toString()實現(xiàn)模板機(jī)制的簡單原理
          //---------------------------------------------------------
          function FontElement(innerHTML) {
          ? this.face = '宋體';
          ? this.color = 'red';
          ? // more...

          ? var ctx = innerHTML;
          ? this.toString = function() {
          ??? return '<Font FACE="' + this.face + '" COLOR="' + this.color + '">'
          ????? + ctx
          ????? + '</FONT>';
          ? }
          }

          var obj = new FontElement('這是一個測試。');

          // 留意下面這行代碼的寫法
          document.writeln(obj);


          ?5). function類型
          ========================
          javascript函數(shù)具有很多特性,除了面向?qū)ο蟮牟糠种?這在后面講述),它自
          已的一些獨特特性應(yīng)用也很廣泛。

          首先javascript中的每個函數(shù),在調(diào)用過程中可以執(zhí)有一個arguments對象。這個
          對象是由腳本解釋環(huán)境創(chuàng)建的,你沒有別的方法來自己創(chuàng)建一個arguments對象。

          arguments可以看成一個數(shù)組:它有l(wèi)ength屬性,并可以通過arguments[n]的方式
          來訪問每一個參數(shù)。然而它最重要的,卻是可以通過 callee 屬性來得到正在執(zhí)行
          的函數(shù)對象的引用。

          接下的問題變得很有趣:Function對象有一個 caller 屬性,指向正在調(diào)用當(dāng)前
          函數(shù)的父函數(shù)對象的引用。

          ——我們已經(jīng)看到,我們可以在JavaScript里面,通過callee/caller來遍歷執(zhí)行
          期的調(diào)用棧。由于arguments事實上也是Function的一個屬性,因此我們事實上也
          能遍歷執(zhí)行期調(diào)用棧上的每一個函數(shù)的參數(shù)。下面的代碼是一個簡單的示例:

          //---------------------------------------------------------
          // 調(diào)用棧的遍歷
          //---------------------------------------------------------
          function foo1(v1, v2) {
          ? foo2(v1 * 100);
          }

          function foo2(v1) {
          ? foo3(v1 * 200);
          }

          function foo3(v1) {
          ? var foo = arguments.callee;
          ? while (foo && (foo != window)) {
          ??? document.writeln('調(diào)用參數(shù):<br>', '---------------<br>');

          ??? var args = foo.arguments, argn = args.length;
          ??? for (var i=0; i<argn; i++) {
          ????? document.writeln('args[', i, ']: ', args[i], '<br>');
          ??? }
          ??? document.writeln('<br>');

          ??? // 上一級
          ??? foo = foo.caller;
          ? }
          }

          // 運行測試
          foo1(1, 2);


          2. JavaScript面向?qū)ο蟮闹С?br />--------
          在前面的例子中其實已經(jīng)講到了object類型的“類型聲明”與“實例創(chuàng)建”。
          在JavaScript中,我們需要通過一個函數(shù)來聲明自己的object類型:
          //---------------------------------------------------------
          // JavaScript中對象的類型聲明的形式代碼
          // (以后的文檔中,“對象名”通常用MyObject來替代)
          //---------------------------------------------------------
          function 對象名(參數(shù)表) {
          ? this.屬性 = 初始值;

          ? this.方法 = function(方法參數(shù)表) {
          ??? // 方法實現(xiàn)代碼
          ? }
          }


          然后,我們可以通過這樣的代碼來創(chuàng)建這個對象類型的一個實例:
          //---------------------------------------------------------
          // 創(chuàng)建實例的形式代碼
          // (以后的文檔中,“實例變量名”通常用obj來替代)
          //---------------------------------------------------------
          var 實例變量名 = new 對象名(參數(shù)表);


          接下來我們來看“對象”在JavaScript中的一些具體實現(xiàn)和奇怪特性。

          ?1). 函數(shù)在JavaScript的面向?qū)ο髾C(jī)制中的五重身份
          ?------
          “對象名”——如MyObject()——這個函數(shù)充當(dāng)了以下語言角色:
          ? (1) 普通函數(shù)
          ? (2) 類型聲明
          ? (3) 類型的實現(xiàn)
          ? (4) 類引用
          ? (5) 對象的構(gòu)造函數(shù)

          一些程序員(例如Delphi程序員)習(xí)慣于類型聲明與實現(xiàn)分開。例如在delphi
          中,Interface節(jié)用于聲明類型或者變量,而implementation節(jié)用于書寫類型
          的實現(xiàn)代碼,或者一些用于執(zhí)行的函數(shù)、代碼流程。

          但在JavaScript中,類型的聲明與實現(xiàn)是混在一起的。一個對象的類型(類)
          通過函數(shù)來聲明,this.xxxx表明了該對象可具有的屬性或者方法。


          這個函數(shù)的同時也是“類引用”。在JavaScript,如果你需要識別一個對象
          的具體型別,你需要執(zhí)有一個“類引用”。——當(dāng)然,也就是這個函數(shù)的名
          字。instanceof 運算符就用于識別實例的類型,我們來看一下它的應(yīng)用:
          //---------------------------------------------------------
          // JavaScript中對象的類型識別
          //?? 語法:? 對象實例 instanceof 類引用
          //---------------------------------------------------------
          function MyObject() {
          ? this.data = 'test data';
          }

          // 這里MyObject()作為構(gòu)造函數(shù)使用
          var obj = new MyObject();
          var arr = new Array();

          // 這里MyObject作為類引用使用
          document.writeln(obj instanceof MyObject);
          document.writeln(arr instanceof MyObject);

          ================
          (未完待續(xù))
          ================
          接下來的內(nèi)容:

          2. JavaScript面向?qū)ο蟮闹С?br />--------

          ?2). 反射機(jī)制在JavaScript中的實現(xiàn)
          ?3). this與with關(guān)鍵字的使用
          ?4). 使用in關(guān)鍵字的運算
          ?5). 使用instanceof關(guān)鍵字的運算
          ?6). 其它與面向?qū)ο笙嚓P(guān)的關(guān)鍵字

          3. 構(gòu)造與析構(gòu)

          4. 實例和實例引用

          5. 原型問題

          6. 函數(shù)的上下文環(huán)境

          7. 對象的類型檢查問題

          ?

          posted on 2006-03-20 09:40 Web 2.0 技術(shù)資源 閱讀(411) 評論(0)  編輯  收藏 所屬分類: Javascript
          主站蜘蛛池模板: 周至县| 常宁市| 郁南县| 土默特左旗| 四会市| 天台县| 灌云县| 宜良县| 长葛市| 乐陵市| 特克斯县| 同德县| 敦煌市| 胶南市| 木里| 始兴县| 长阳| 嘉兴市| 镇坪县| 大庆市| 萨嘎县| 阜城县| 金溪县| 钟山县| 栾城县| 永春县| 政和县| 师宗县| 米脂县| 行唐县| 霍林郭勒市| 盐亭县| 田林县| 渑池县| 含山县| 三江| 象州县| 安溪县| 盱眙县| 若羌县| 文昌市|