我學Ajax企業級開發 之 Ajax構建塊

sz_bdqn發表於2010-10-23

我學Ajax企業級開發 Ajax構建塊

 

一、簡介

       這些內容主要是記錄一些我曾經學過的知識,在此記錄下做過總結,希望對以後所有幫助。今天學習的是Ajax企業開發第二章。

二、學習內容

2.1 Javascript

2.1.1 JavaScript型別

       Javascript3中原始型別:布林型、字串和數值型。

       2中特殊的型別:null undefined

       複合型別物件型別:array/function

 

2.1.2 閉包

       Javascript中,閉包(closure)也許是最重要和最不容易理解的特性,它也是動態程式語言一種共同的特性。當在一個函式內部宣告另一個函式(也叫做內部函式)時,就形成了Javascript的閉包。

當一個函式在另一個函式內部被定義時,內部函式可以訪問外部函式定義的任何變數,甚至在外部函式執行完畢後,他仍然可以訪問。通過Javascript解析器,外部函式的作用域被動態地附加到內部函式的作用域裡。例如:

function Foo() {

  var bar = "foobar";

  // create the inner function or closure

  var showFoobar = function() {

    alert(bar);

  };

  // return a reference to the dynamically created closure

  return showFoobar;

}

 

var myClosure = Foo();

myClosure(); // alerts "foobar"

// or

Foo()(); // alerts "foobar"

 

 

2.1.3 物件導向JavaScript

2.1.3.1 公共成員

function Customer(firstName, lastName) {

  this.firstName = firstName;

  this.lastName = lastName;

  this.getFullName = function() {

    return this.firstName + " " + this.lastName;

  };

}

 

2.1.3.2 私有成員

function Customer(firstName, lastName) {

  var _firstName = firstName;

  var _lastName = lastName;

  this.getFullName = function() {

    return _firstName + " " + _lastName;

  };

}

 

2.1.4 prototype屬性

function Customer(firstName, lastName) {

  this.firstName = firstName;

  this.lastName = lastName;

}

 

Customer.prototype.getFullName = function() {

  return this.firstName + " " + this.lastName;

}

 

 

       Javascript中的Function物件包含了一個稱為prototype的特殊屬性。通過它可以擴充套件類的定義。這也是Javascript稱為一種原型語言的由來。

       通過使用prototype屬性對類做出的擴充套件疆會應用到這個類的所有例項,包括任何建立的新例項。在物件初始化之後還可以給它增加欄位或者方法,大多數面嚮物件語言都不支援這種思想,然而,這卻讓JavaScript更富內涵和更具表現力。

       通過一個類的prototype屬性定義的欄位和方法能夠被這個類在任何時刻初始化的例項所訪問,其原因是當類通過new關鍵字建立物件時,在類的prototype屬性和這個物件之間建立了一個隱藏的連線。然後當訪問這個物件的欄位或者方法時,首先會檢查自己是否擁有這個欄位或者方法。如果沒有,就會在物件的prototype屬性引用的物件裡查詢。如果在prototype屬性所有引用的物件裡面沒有找到,它會在這個引用物件的prototype屬性裡查詢,如此遞迴查詢。

2.1.5 物件導向程式設計和繼承

entAjax.extend = function(subClass, baseClass) {

  function inheritance() {};

  inheritance.prototype = baseClass.prototype;

 

  subClass.prototype = new inheritance();

  subClass.baseConstructor = baseClass;

  if (baseClass.base) {

    baseClass.prototype.base = baseClass.base;

  }

  subClass.base = baseClass.prototype;

}

 

function parentClass() {/*class contents here*/}

function subClass(){

  subClass.baseConstructor.apply(this, arguments);

}

entAjax.extend(subClass, parentClass);

subClass.prototype.foo = function(args) {

  subClass.base.foo.apply(this, arguments);

}

  function inheritance() {};

  inheritance.prototype = baseClass.prototype;

       這個功能通過建立一個空建構函式的臨時類(當然,只有一個函式)來完成。接下來women你把這個臨時類的prototype屬性設定為積累的prototype屬性,這種做法意味著除了臨時類的建構函式沒有程式碼並且基類的建構函式還沒有被呼叫外,臨時類和基類現在是完全一樣的。這是一個重要的必要條件,因為基類的建構函式可能會做一些DOM操作,這些操作在類被例項化之前不應該被實際地執行

在臨時類建立之後,例項化臨時類時類並且把子類的prototype守護星設定為這個臨時類的例項,實際上也是基類的例項。

Subclass.prototype = new inheritance();

 

2.1.6易變性

       .

2.1.7 執行緒

var i = 0;

function poll(){

       alert(i++);

}

window.setInterval(poll,1);

 

2.1.8 錯誤處理

       JavaScript提供和JavaC#類似的處理方式。try/catch/finally 宣告塊。在Catch塊中,我們可以通過訪問錯誤物件瞭解到底是什麼原因引起了這個錯誤。通過錯誤物件暴露出的屬性可以訪問錯誤資訊(message)、描述(decription)、名稱(name)以及數值(number)屬性。例如:

try {

  var n = Math.random();

  if (n > 0.5) throw new Error("n is less than 0.5");

}catch(err){

  // Deal with the native error object here

  alert(err.message + " ?" + err.name);

}finally{

  // Do cleanup here if need be

}

 

 

2.1.9 名稱空間

if (typeof entAjax == "undefined") {

  entAjax = {};

}

       名稱空間是防止物件、屬性、函式或者方法名稱互相沖突的一種方式。

2.1.10瀏覽器型別

var ua = navigator.userAgent;

entAjax.IE = (ua.indexOf("MSIE") > 0?true:false); // Internet Explorer

entAjax.FF = (ua.indexOf("Firefox") > 0?true:false); // Firefox

entAjax.SF = (ua.indexOf("Apple") > 0?true:false); // Safari

 

2.2DOM

2.2.1 基本原理

2.2.2 操作DOM

 

2.3CSS

2.4事件

2.4.1 事件流

       DOM事件標準定義了兩種事件流,這兩種事件流有著顯著的不同並且可能對應有著相當大的影響。這兩種事件流分別是捕獲(capture)和冒泡(bubble)。

       預設情況下,事件使用冒泡事件流,不使用捕獲事件流。在冒泡過程中的任意時刻都可以終止事件的冒泡,在遵從W3C標準的瀏覽器裡可以通過呼叫事件物件上的stoppropagetion()方法來好ixian,在IE裡可以通過設定物件cancelBubble屬性為true實現。如果不停止傳播,事件將一直通過DOM冒泡直接到達文件結點。舉個例如如下:

function test(){

     alert('你好!');

}

function test1(e){

     alert("Hello");

     e.cancelBubble = true;  //IE中使用

     //e.stopPropagation();  //遵從W3C標準的瀏覽器

}

<div style="border:1px solid #999999; width:500px; height:300px;" onclick="test()">

     <input type="button" value="點選" onclick="test1(event)" />

</div>

 

2.4.2 事件繫結

2.4.2.1 內聯事件

<div onclick="nameClicked(event)">John Doe</div>

 

2.4.2.2 程式設計式定義事件處理函式

var domFirstName = document.getElementById("firstName");

domFirstName.onclick = function(){}

 

 

2.4.2.3 事件註冊

 

var domFirstName = document.getElementById("firstName");

if (entAjax.IE) {

     domFirstName.attachEvent("onclick", nameClicked);

} else {

     domFirstName.addEventListener("click", nameClicked, false);

}

 

 

2.4.3 跨瀏覽器事件

       當以跨瀏覽器的方式處理事件時存在兩個主要的問題。首先,幾乎所有的瀏覽器都遵循W3C DOM的事件的標準來實現他們的市靜安模型。IE仍然是個例外。在另一方面,在IE中,this關鍵字在事件回撥方法中引用的卻是Javascript執行的上下文,這個上下文可能是一個Javascript物件。

entAjax.EventManager = {};

entAjax.EventManager.attachEvent = function(element, type, callback, setCapture) {

  // Browser checking for IE vs W3C compliant browser

  if (element.attachEvent) {

    // Create two expando properties with function references

    element['ntb_' + type] = function() {

      callback.call(element);

    };

    // Attach one of our expando function references to the event

    element.attachEvent('on'+type, element['ntb_' + type]);

    // Set the capture if it was specified

    if (setCapture) element.setCapture(true);

  }

  else if (element.addEventListener) {

    element.addEventListener(type, callback, setCapture);

  }

}

 

 

2.4.4 事件物件

    略。

2.5 客戶端/伺服器通訊

2.5.1 XMLHttpRequet基礎知識

var xhr = null;

if (entAjax.IE6) {

  xhr = new ActiveXObject("Microsoft.XMLHTTP");

} else if (entAjax.IE7 || entAjax.FF || entAjax.SF || entAjax.OP) {

  xhr = new XMLHttpRequest();

} else {

  // no XHR so we are out of luck, maybe degrade and use an IFRAME?

}

xhr.open("GET", "http://www.example.com/myResource", false);

xhr.send(null);

這段程式碼是定義XHR物件最簡單的一種方式。建立XHR物件之後,我們為onreadystatechange事件指定一個回撥函式。當XHR物件的eadyState屬性改變時,這個回撥函式會被觸發。最終我們呼叫XHR物件的open()方法建立一個到伺服器連線,open()方法一般有3個引數,分別是:請求型別(GETPost等等),伺服器資源URL,一個指定請求時同步(false)還是非同步(true)的標記,除此之外我們還可以為受保護的資源傳送一個可選擇的使用者名稱和密碼。開啟之後我們只需要用send(data)方法,這個方法接收任何資料作為唯一的引數,然後將資料傳送到伺服器,接著請求開始執行。

 

2.5.1.1 XHR工廠模式

   下面有作介紹,此處略。

2.5.1.2 非同步請求

       為了非同步傳送請求,我們需要實現兩個操作。首先,需要為XHR物件的onreadystatechange屬性指定一個事件處理函式,這個函式在XHR物件的readyState屬性改變時被觸發。其次,我們需要設定傳入open()方法的第三個引數為true,告訴XHR物件我們想要傳送的是非同步請求。

entAjax.HttpRequest = function() {

  this.handler = "";

  this.async = true;

  this.responseType = "xml";

  this.httpObj = entAjax.XHRFactory.createXHR();

}

 

entAjax.HttpRequest.prototype.get = function() {

  this.httpObj.open("GET", this.handler, this.async);

  this.httpObj.onreadystatechange = entAjax.close(this, this.requestComplete);

  if (this.responseType == "xml")

    this.httpObj.setRequestHeader("Content-Type","text/xml");

  this.httpObj.send(null);

}

 

entAjax.HttpRequest.prototype.requestComplete = function() {

}

 

entAjax.HttpRequest.prototype.abort = function() {

  this.httpObj.onreadystatechange = function () {};

  this.httpObj.abort();

}

 

var xhr = new entAjax.HttpRequest();

xhr.handler = "http://www.example.com/myResource";

xhr.get();

 

2.5.1.3 伺服器響應

       在非同步請求環境中設定到onreadystatechange事件的事件的處理函式非常重要,因為這個函式會在請求完成後通知我們,在得到通知後,我們才可以訪問來自伺服器的的響應。在這個事件處理中,我們也需要執行兩個操作。首先,我們要檢查XHR物件的readyState屬性值。這個屬性值是04之間的任意值,這5個值分別表名請求未初始化(uninitialized)、正在載入(loading)、載入完畢(loaded)、伺服器互動中(interactive)和已完成(complete)

 

entAjax.HttpRequest = function() {

  this.handler = "";

  this.async = true;

  this.responseType = "xml";

  this.httpObj = entAjax.XHRFactory.createXHR();

  this.completeCallback = null;

}

 

entAjax.HttpRequest.prototype.requestComplete = function() {

  if (this.httpObj.readyState == 4) {

    if (this.httpObj.status == 200) {

      this.completeCallback.call(this, this);

    }

  }

}

 

var xhr = new entAjax.HttpRequest();

xhr.async = true;

xhr.handler = "http://www.example.com/myResource";

xhr.completeCallback = showResult;

xhr.get();

 

2.5.1.4 將資料放鬆到伺服器

      

entAjax.HttpRequest = function() {

  this.handler = "";

  this.async = true;

  this.responseType = "xml";

  this.httpObj = entAjax.XHRFactory.createXHR();

  this.completeCallback = null;

  this.params = {};

}

 

entAjax.HttpRequest.prototype.post = function(sData) {

  // Either send the provided data or the params

  if (sData == null) {

    sData = "";

    for (var name in this.params) {

      sData += escape(name) + "=" + escape(this.params[name]) + "&";

    }

    sData = sData.substring(0, sData.length-1);

  }

  // Now send the data using a POST

  this.httpObj.open("POST", this.handler, this.async);

  this.httpObj.onreadystatechange = entAjax.close(this, this.requestComplete);

  if (this.responseType == "xml")

    this.httpObj.setRequestHeader("Content-Type","text/xml");

  this.httpObj.send(sData);

}

 

entAjax.HttpRequest.prototype.setParam = function(name, value) {

  if (value == null)

    delete this.params[name];

  else

    this.params[name] = value;

}

 

var myXHR = new entAjax.HttpRequest();

myXHR.setParam("firstName","John");

myXHR.setParam("lastName","Doe");

myXHR.setParam("id","1234");

myXHR.handler = "customers/save";

myXHR.post(); // or myXHR.get(), either way the params get sent back

 

2.5.2 處理資料

2.5.2.1 XML

var xhr = new entAjax.HttpRequest();

xhr.completeCallback = buildCustomerList;

xhr.handler = "http://www.example.com/myResource";

xhr.get();

 

function buildCustomerList(xhr) {

  var html = "<div>";

  // do DOM methods for creating nodes in the web page etc.

  var xResponse = xhr.httpObj.responseXML;

  var aCustomers = xResponse.getElementsByTagName("Customer");

  var len = aCustomers.length;

  for (var i=0; i<len; i++) {

    customer = aCustomer[i];

    html += "<span>" + customer.getElementsByTagName("firstName")[0].text+"</span>";

    html += "<span>" + customer.getElementsByTagName("lastName")[0].text+"</span>";

  }

  return html + "</div>";

}

 

2.5.2.2 JavaScript物件表示法(JSON

       對格式化資料而言,除了了XML資料格式,另一種流行的選擇是使用Javascript物件表示法(JSON),Json是一種資料序列化格式,它使用一種語法來表示基本的資料結構。

       對於Javascript而言,Json之所以變得如此流行,是因為攢在雙重的原因。首先,可以使用Javascripteval()函式執行它,把它例項化一個Javascript物件。其次,Json資料,因為它可以跨域傳遞,所以可以使得人們做到一些更加有趣的事情。

var Customer = eval('({"firstName":"John","lastName":"Doe"})');

alert(Customer.firstName);

 

2.6 本章中JS所用到的設計模式

2.6.1 單例模式

entAjax.Info = {

    ver:"1.0",

    status:"active"

};

單例模式(Singlton Pattern):單例模式保證一個類僅有一個例項,並且提供一個訪問它的全域性訪問點。單件在Java中得到了廣泛的應用,並且在JavaScript中也可以容易實現。當一個物件需要在整個系統中協調工作時,單件非常有用。某種型別的一個全域性變數應用資訊就是一個單件的一個例子,這個類包括了版本、狀態等資訊,這樣一個類僅僅需要一個例項。,在Javascript中採用字面量的語法方式處理單件。如上程式碼所示。

 

2.6.2 裝飾模式

entAjax.Panel = function() {

  this.title = "Standard Panel";

}

var myWindow = new entAjax.Panel();

// Make myWindow scrollable

myWindow.scroll = function() { }

 

裝飾模式(Decorator Pattern)允許動態的給物件新增一些額外的行為。裝飾圍繞原始物件包裹出一個新的物件並給這個物件新增功能,同時,新物件與原始物件的介面必須保持一致。相對於繼承來說裝飾模式是一種更為靈活的選擇,不同點在於繼承是在編譯期給予子類增加功能而裝飾器是在執行期。使用裝飾器,你可以給一個單獨物件增加功能而保留其他物件不被修改。

 

2.6.3 工廠模式

entAjax.XHRFactory = {

  createXHR: function() {

    try {

      if (entAjax.IE6) {

        xhr = new ActiveXObject("Microsoft.XMLHTTP");

      } else if (entAjax.IE7 || entAjax.FF || entAjax.SF || entAjax.OP) {

        xhr = new XMLHttpRequest();

      } else {

        // no XHR, maybe degrade and use an IFRAME?

        throw("XHR not supported in your browser");

      }

    } catch(e) {

      // no XHR object available ?think about degrading

      alert(e.message);

    }

    return xhr;

  }

}

var xhr = entAjax.XHRFactory.createXHR();

    簡單工廠模式是類的建立模式。簡單工廠模式是一個工廠決定建立出哪一類產品的例項。

 

       外觀模式:在Javascript中一個經常被應用到的設計模式。當為了簡化火勢為了讓調另外一個API變得更加容易而建立一個新的API或者介面時,經常會用到外觀模式。在Javascript裡我們經常使用這個模式來隱藏跨瀏覽器開發的複雜性。例如,我們可以使用外觀模式簡單的呼叫一個唯一的事件方法,也可以每次都去檢查當前的瀏覽器型別然後再去呼叫各自的函式,顯然,前者要比後者好很多。

 

對於這些不夠理解可以參考其他的專門講設計模式的書籍如:《JAVA與模式》《大話設計模式》等。

 

三、總結

       這裡重新複習了JavaScript的一些知識。如Javascript的資料型別、DOMCSS、事件XHR等。也介紹了有關設計模式在Javascript中的運用,在這裡列出了單例模式、工廠模式、裝飾模式。

四、資源下載

相關文章