This page looks plain and unstyled because you're using a non-standard compliant browser. To see it in its best form, please visit upgrade to a browser that supports web standards. It's free and painless.

Fillano's Learning Notes 會員登入 會員註冊

這幾天自己重新寫一個小的ajax post工具,希望它可以同時存在多個實體,同一個實體也可以重複使用,但是在測試同一個實體重複使用時,發現了一個小問題。問題是在IE平台上出現的:

測試用的php,相當於echo,只是單純把post陣列印出:

print_r($_POST);

接下來是測試的網頁:

var fwajax = function() {
	this.updating = false;
	var query = {};
	var thisref = this;
	var ajax = (function() {
		try{ return new ActiveXObject("Msxml2.XMLHTTP.3.0") }catch(e){}
		try{ return new ActiveXObject("Msxml2.XMLHTTP") }catch(e){}
		try{ return new ActiveXObject("Microsoft.XMLHTTP") }catch(e){}
		try{ return new XMLHttpRequest();} catch(e){}
		return null;
	})();
	function checkstate (callback) {
		switch (ajax.readyState) {
			case 1: break;
			case 2: break;
			case 3: break;
			case 4:
				callback(ajax.responseText,ajax.responseXML,ajax.status);
				thisref.updating = false;
		}
	}
	this.addQuery = function(name, value) {
		query[encodeURIComponent(name)] = encodeURIComponent(value);
	}
	this.request = function(method, url, callback) {
		try {
		this.updating = true;
		var qstr = "";
		for(var i in query) {
			qstr += i + "=" + query[i] + "&";
		}
		query = {};
		ajax.onreadystatechange = function() {
			checkstate(callback);
		};
		ajax.open(method, url, true);
		ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		ajax.send(qstr);
	}catch(e){alert(e);}
	}
}
var a = new fwajax();
function test() {
	if(!a.updating){
		a.addQuery("key1","value1");
		a.addQuery("key2","value2");
		a.request("POST", "test279.php", function(a,b,c){alert(a);});
	} else {
		alert("updating!");
	}
}

然後用一個按鈕處發test()。測試結果發現,第一次按下按鈕時沒問題,第二次按下按鈕就沒反應了。仔細檢查了一下,發現似乎onreadystatechange沒有觸發,或是沒有正確assign一個function做event handler。

經過稍為調整,發現有兩個方法可以修正:

  1. 把onreadystatechange的assign動作移到呼叫open()方法之後
  2. 使用新版的xml物件(除非是使用vista,使用者不一定會安裝msxml6.0...用處不大)

經過修改後,程式可以順利執行了:

var fwajax = function() {
	this.updating = false;
	var query = {};
	var thisref = this;
	var ajax = (function() {
		try{ return new ActiveXObject("Msxml2.XMLHTTP.6.0") }catch(e){}
		try{ return new ActiveXObject("Msxml2.XMLHTTP.3.0") }catch(e){}
		try{ return new ActiveXObject("Msxml2.XMLHTTP") }catch(e){}
		try{ return new ActiveXObject("Microsoft.XMLHTTP") }catch(e){}
		try{ return new XMLHttpRequest();} catch(e){}
		return null;
	})();
	function checkstate (callback) {
		switch (ajax.readyState) {
			case 1: break;
			case 2: break;
			case 3: break;
			case 4:
				callback(ajax.responseText,ajax.responseXML,ajax.status);
				thisref.updating = false;
		}
	}
	this.addQuery = function(name, value) {
		query[encodeURIComponent(name)] = encodeURIComponent(value);
	}
	this.request = function(method, url, callback) {
		try {
		this.updating = true;
		var qstr = "";
		for(var i in query) {
			qstr += i + "=" + query[i] + "&";
		}
		query = {};
		ajax.open(method, url, true);
		ajax.onreadystatechange = function() {
			checkstate(callback);
		};
		ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		ajax.send(qstr);
	}catch(e){alert(e);}
	}
}
var a = new fwajax();
function test() {
	if(!a.updating){
		a.addQuery("key1","value1");
		a.addQuery("key2","value2");
		a.request("POST", "test279.php", function(a,b,c){alert(a);});
	} else {
		alert("updating!");
	}
}

兩個方法都用上了,只是assign動作必須放在open()之後不太合理...(firefox就沒問題阿)

因為需要寫一個陣列查詢的功能,希望用起來簡單,所以想要用類似sql語句的方式來使用,想到的作法就是在方法最後return this。 例如寫一個叫做aql的函數:

function aql() {
	this.select = function(a) {
		this.selection = a;
		return this;
	};
	this.from = function(a) {
		this.fromArray = a;
		return this;
	};
	this.where = function(a) {
		this.whereCriteria = a;
		return this;
	};
	this.orderby = function(a) {
		this.order = a;
		return this;
	};
	this.query = function() {
		if(this.selection) alert(this.selection);
		if(this.fromArray) alert(this.fromArray);
		if(this.whereCriteria) alert(this.whereCriteria);
		if(this.order) alert(this.order);
	}
}

傳統的使用方式像這樣:

var a = new aql();
a.select([0,1]);
a.from([[1,'abc',2334],[2,'def',84850],[3,'ghi',3884]]);
a.where([0,'=',2]);
a.orderby([0]);
a.query();

但是使用return this的話,就可以用更簡潔的語法,好像在使用sql:

new aql().select([0,1]).from([[1,'abc',2334],[2,'def',84850],[3,'ghi',3884]]).where([0,'=',2]).orderby([0]).query();
(這裡舉的例子並沒有實做查詢的功能,只是驗證return this的作法可行。)


2008-10-4 0:12 補充

前幾天在Crockford的書《Javascript: 優良部分》中看到,他把這個方法稱作Cascade