JavaScript物件導向的支援(1)

來源:互聯網
上載者:User
javascript|對象

================================================================================
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)
================================================================================


八、JavaScript物件導向的支援
~~~~~~~~~~~~~~~~~~
很少有人對JavaScript的物件導向特性進行系統的分析。我希望接下來的文字讓你瞭解到這
個語言最少為人知的一面。


1. JavaScript中的類型
--------
雖然JavaScript是一個基於對象的語言,但對象(Object)在JavaScript中不是第一型的。JS
是以函數(Function)為第一型的語言。這樣說,不但是因為JS中的函數具有進階語言中的函
數的各種特性,而且也因為在JS中,Object也是由函數來實現的。——關於這一點,可以在
後文中“構造與析構”部分看到更進一步的說明。

JS中是弱類型的,他的內建類型簡單而且清晰:
---------------------------------------------------------
undefined : 未定義
number    : 數字
boolean   : 布爾值
string    : 字串
function  : 函數
object    : 對象

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

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

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

這一行代碼還有一點是需要說明的,就是void語句的應用。void表明“執行其後的語句,且
忽略傳回值”。因此在void之後可以出現能被執行的任何“單個”語句。而執行的結果就是
undefined。當然,如果你願意,你也可以用下面的代碼之一“定義undefined”。
//---------------------------------------------------------
// 1. 較複雜的方法,利用一個匿名的空函數執行的返回
//---------------------------------------------------------
var undefined = function(){}();

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

void也能像函數一樣使用,因此void(0)也是合法的。有些時候,一些複雜的語句可能不能
使用void的關鍵字形式,而必須要使用void的函數形式。例如:
//---------------------------------------------------------
// 必須使用void()形式的複雜運算式
//---------------------------------------------------------
void(i=1);       // 或如下語句:
void(i=1, i++);


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

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

全域對象(Gobal)中還有兩個屬性與number類型的運算有關:
  NaN      : 算術運算式的運算結果不是數字,則返回NaN值。
  Infinity : 比MAX_VALUE更大的數。

如果一個值是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表示比最大的數 (Number.MAX_VALUE) 更大的值。在JS中,
它在數學運算時的價值與正無窮是一樣的。——在一些實用技巧中,它也可以用來做一
個數組序列的邊界檢測。

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

與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類型相關的方法有:
 isFinite()   : 如果值是NaN/正無窮/負無窮,返回false,否則返回true。
 parseFloat() : 從字串(的首碼部分)取一個浮點數。不成功則返回NaN。


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

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

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

下例說明這個問題:
//---------------------------------------------------------
// toString()的應用
//---------------------------------------------------------
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);

在這個例子中,我們看到,當一個對象沒有重新聲明(覆蓋)自己toString()方
法的時候,那麼它作為字串型態使用時(例如被writeln),就會調用Java Script
環境預設的toString()。反過來,你也可以重新定義JavaScript理解這個對象
的方法。

很多JavaScript架構,在實現“模板”機制的時候,就利用了這個特性。例如
他們用這樣定義一個FontElement對象:
//---------------------------------------------------------
// 利用toString()實現模板機制的簡單原理
//---------------------------------------------------------
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函數具有很多特性,除了物件導向的部分之外(這在後面講述),它自
已的一些獨特特性應用也很廣泛。

首先javascript中的每個函數,在調用過程中可以執有一個arguments對象。這個
對象是由指令碼解釋環境建立的,你沒有別的方法來自己建立一個arguments對象。

arguments可以看成一個數組:它有length屬性,並可以通過arguments[n]的方式
來訪問每一個參數。然而它最重要的,卻是可以通過 callee 屬性來得到正在執行
的函數對象的引用。

接下的問題變得很有趣:Function對象有一個 caller 屬性,指向正在調用當前
函數的父函數對象的引用。

——我們已經看到,我們可以在JavaScript裡面,通過callee/caller來遍曆執行
期的調用棧。由於arguments事實上也是Function的一個屬性,因此我們事實上也
能遍曆執行期調用棧上的每一個函數的參數。下面的代碼是一個簡單的樣本:

//---------------------------------------------------------
// 調用棧的遍曆
//---------------------------------------------------------
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('調用參數:<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物件導向的支援
--------
在前面的例子中其實已經講到了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物件導向的支援
--------

 2). 反射機制在JavaScript中的實現
 3). this與with關鍵字的使用
 4). 使用in關鍵字的運算
 5). 使用instanceof關鍵字的運算
 6). 其它與物件導向相關的關鍵字

3. 構造與析構

4. 執行個體和執行個體引用

5. 原型問題

6. 函數的上下文環境

7. 對象的類型檢查問題



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.