首頁 >web前端 >js教程 >jQuery鍊式運算如何實作以及為什麼要用鍊式運算_jquery

jQuery鍊式運算如何實作以及為什麼要用鍊式運算_jquery

WBOY
WBOY原創
2016-05-16 17:43:311652瀏覽
兩個問題
1.jQuery的鍊式運算是如何實現的?
2.為什麼要用鍊式運算?
大家認為這兩個問題哪個好回答一點呢?

鍊式操作
原理相信百度一下一大把,實際上鍊式操作只是透過物件上的方法最後
return this
把物件再返回回來,物件當然可以繼續呼叫方法啦,所以就可以鍊式操作了。那麼,簡單實作一個:
複製程式碼 程式碼如下:


程式碼如下:




//定義一個JS類別
function Demo() {
}
//擴充它的prototype
Demo.prototype ={
setName:function (name) {
this. name = 名稱;
return this;
},
getName:function () {
return this.name;
},
setAge:function (age) {
this.age = age;
return this;
}
};
////工廠函數
function D() {
return new Demo();
} //去實作可鍊式的呼叫D().setName("CJ").setAge(18).setName();


但…為什麼要用呢?

複製程式碼

程式碼如下:


document.getElementById("ele").dosomething();
document.getElementById("ele").dootherthing();

複製代碼


代碼如下:


var ele = document.getElementById("ele" );
ele.dosomething();
ele.dootherthing();

而且兩行並沒有比一行多多少程式碼,甚至對應的封裝反而使得程式碼更多了。 最糟糕的是所有物件的方法回傳的都是物件本身,也就是說沒有回傳值,這不一定在任何環境下都適合。 舉個例子,我們想弄一個超大整數BigInteger(意思是如果用Javascript的Number保存可能會溢出的整數),順便擴展他的運算方法,會適合用鍊式操作麼? 例如運算31415926535 * 4 - 271828182,如果設計成鍊式風格的方法可能會是這樣的:

複製碼>
程式碼如下:

var result = (new BigInteger("31415926535")).multiply(new BigInteger("4")).subtract(new BigInteger("271828182") .val();
console.log("result == " result); 複製程式碼


程式碼如下:


var bigIntInteger" 31415926535");
var result1 = bigInteger.multiply(new BigInteger("4")).val(); var result2 = bigInteger.subtract(new BigInteger("271828182").bigInteger; console.log("result1 == " result1 ", result2 == " result2);
這似乎一點也不優雅了,和不用鍊式操作沒啥不同嘛!
那如果要求是原來的BigInteger不能改變呢?好吧,鍊式操作似乎不能滿足這個需求了。

那到底為什麼要用鍊式運算呢?
為了更好的非同步體驗
Javascript是無阻塞語言,所以他不是沒阻塞,而是不能阻塞,所以他需要透過事件來驅動,異步來完成一些本來需要阻塞進程的操作。

但是非同步程式設計是一種令人瘋狂的東西…運行時候是分離的倒不要緊,但是編寫程式碼時候也是分離的就…
常見的非同步程式設計模型有哪些呢?
回調函數
所謂的回呼函數,意指先在系統的某個地方對函數進行註冊,讓系統知道這個函數的存在,然後在以後,當某個事件發生時,再呼叫這個函數對事件進行回應。
複製程式碼 程式碼如下:

function f(num, callback){
if (numalert("呼叫低層函數處理!");
alert("分數不能為負,輸入錯誤!");
}else if(num==0){
alert("呼叫低階函數處理!");
alert("該學生可能未參加考試!");
}else{
alert("呼叫高層函數處理!");
setTimeout(function(){callback();}, 1000);
}
}

這裡callback則是回呼函數。可以發現只有當num為非負數時候callback才會呼叫。
但是問題,如果我們不看函數內部,我們並不知道callback會幾時調用,在什麼情況下調用,代碼間產生了一定耦合,流程上也會產生一定的混亂。

雖然回呼函數是一種簡單而易於部署的實現非同步的方法,但從程式設計體驗來說它卻不夠好。
事件監聽
也就是採用事件驅動,執行順序取決於事件順序。
複製程式碼 程式碼如下:

function EventTarget(){


function EventTarget(){
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget,
addHandler: function(type, handler){
this.handlers[type] = [];
},
fire: function(){
if(!event.target){
event.target = this;
}
if(this.handlers[event.type instanceof Array] ){
var handlers = this.handlers[event.type];
for(var i = 0, len = handlers.length, i handlers[i](event) ;
}
}
},
removeHandler: function(type, handler){
if(this.handlers[type] instanceof Array){
var handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers = this.handlers [類型];
for(var i = 0, le = handlers.length; i if(handlers[i] === handler){
break;
}
}
handlers.splice(i, 1);
}
}
};


上面是《JavaScript高級程式設計》中的自白定義事件實作。於是我們就可以透過addHandler來綁定事件處理函數,用fire來觸發事件,用removeHandler來刪除事件處理函數。 雖然透過事件解耦了,但流程順序更混亂了。

鍊式非同步
個人覺得鍊式操作最值得稱讚的還是其解決了非同步程式設計模型的執行流程不清晰的問題。 jQuery中$(document).ready就非常好的詮釋了這個理念。 DOMCotentLoaded是一個事件,在DOM並未加載前,jQuery的大部分操作都不會奏效,但jQuery的設計者並沒有把他當成事件一樣來處理,而是轉成一種“選其對象,對其操作”的思路。 $選擇了document對象,ready是其方法進行操作。這樣子流程問題就非常清楚了,在鏈條越後位置的方法就越後執行。 複製程式碼
程式碼如下:

(function(){
var isReady=false; //判斷onDOMReady方法是否已經被執行過
var readyList= [];//把需要執行的方法先暫存在這個陣列裡
var timer;//定時器句柄
ready=function(fn) {
if (isReady )
fn.call( document);
else
readyList.push( function() { return fn.call(this);});
return this;
}
var onDOMReady=function(){
for(var i=0;ireadyList[i].apply(document);
}
readyList = null;
}
var bindReady = function(evt){
if(isReady) return;
isReady=true;
onDOMReady.call(window);
if(document.removeEventListener){
document.removeEventListener("DOMContentLoaded", bindReady, fsese); if(document.attachEvent){
document.detachEvent("onreadystatechange", bindReady);
if(window == window.top){
clear(timer);
timer = null }
}
};
if(document.addEventListener){
document.addEventListener("DOMContentLoaded", bindReady, false);
}el Event(documentse.
document.attachEvent("onreadystatechange", function(){
if((/loaded|complete/).test(document.readyState))
bindReady();
});
if(window == window.top){
timer = setInterval(function(){
try{
isReady||document.documentElement.doScroll('left');//在IE下用能否執行doScroll判斷dom是否載入完成
}catch(e){
return;
}
bindReady();
},5);
}
}
})();


上面的程式碼不能用$(document).ready,而應該是window.ready。

Promise
CommonJS中的非同步程式設計模型也延續了這個想法,每個非同步任務返回一個Promise對象,該物件有一個then方法,允許指定回調函數。
所以我們可以這樣寫
f1().then(f2).then(f3); 這種方法我們不需要太過關注實現,也不太需要理解異步,只要懂得透過函數選對象,透過then進行操作,就能進行非同步程式設計。
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn