從jQuery談庫(kù)與框架的設(shè)計(jì)之優(yōu)劣
jQuery是業(yè)內(nèi)知名的javascript框架,它的實(shí)現(xiàn)和設(shè)計(jì)可以說(shuō)代表了javascript界***的水平,本文試從四個(gè)方面來(lái)以jQuery為例總結(jié)庫(kù)與框架設(shè)計(jì)的原則和優(yōu)劣判斷。
解決問(wèn)題
首先請(qǐng)看一個(gè)我實(shí)現(xiàn)的框架,我把這個(gè)庫(kù)稱(chēng)為四則運(yùn)算。
- function add(a,b) {
- return a+b;
- }
- function mul(a,b) {
- return a*b;
- }
- function minus(a,b) {
- return a-b;
- }
- function div(a,b) {
- return a/b;
- }
這個(gè)庫(kù)的API簡(jiǎn)潔優(yōu)美,實(shí)現(xiàn)的更是優(yōu)雅無(wú)比,它把四則運(yùn)算統(tǒng)一成了函數(shù)形式,使得我們的開(kāi)發(fā)更加方便。***大的是,這個(gè)做法使得四則運(yùn)算支持函數(shù)式編程,比如:
- function acc(a,b,f) {
- var jieguo = a; //http://weibo.com/2178807082/zk1kOcMPU
- for(var i = 1; i<b; i++) {
- jieguo = f(jieguo,a);
- }
- return jieguo
- }
這樣,通過(guò)acc函數(shù),我們可以輕易實(shí)現(xiàn)n次方運(yùn)算,這正是函數(shù)式編程之美。
舉這個(gè)例子是為了告訴大家,一個(gè)框架/庫(kù)其實(shí)可以不需要解決任何問(wèn)題——只要你會(huì)亂用概念、自吹和哄騙新手就夠了。
下面我們來(lái)看看一個(gè)非常成功的框架——jQuery解決的問(wèn)題,讓我們來(lái)看看jQuery首頁(yè)的"Brief Look"中給出的***個(gè)例子。
- DOM Traversal and Manipulation
- $( "button.continue" ).html( "Next Step..." )
嗯,沒(méi)錯(cuò),jQuery希望幫助我們解決遍歷DOM的問(wèn)題,如果沒(méi)有jQuery,我們大概要寫(xiě)一個(gè)traversal函數(shù)了。
- function traversal(node, f) {
- f(node);
- if(node.children.length) {
- for(var i = 0; i<node.children.length;i++)
- traversal(node.children[i],f);
- }
- }
- traversal(document.body,function(element){
- if(element.tagName=="button" && element.className.match(/continue/)) {
- element.innerHTML = "Next Step...";
- }
- })
traversal這個(gè)函數(shù)真的是超麻煩不是么?竟然有175個(gè)字符呢!使用起來(lái)也有166個(gè)字符,用了jQuery之后,只要45個(gè)字符就可以搞定呢!好神奇!
好吧原諒我剛才把思維模式切換到了"write less, do more"模式,jQuery正是通過(guò)一個(gè)字符一個(gè)字符地節(jié)約程序員的工作量來(lái)達(dá)到這一偉大目標(biāo)的。
壓縮后仍達(dá)97k的jQuery竟然幫助我們少寫(xiě)了這么多代碼,好神奇啊啊??!這正是庫(kù)/框架設(shè)計(jì)的要點(diǎn),那就是"沒(méi)有問(wèn)題創(chuàng)造問(wèn)題也要解決問(wèn)題!"
命名
命名問(wèn)題對(duì)于庫(kù)/框架來(lái)說(shuō),尤其重要。
總的來(lái)說(shuō),如同正統(tǒng)程序員那樣追求命名的易讀、易懂、與原生一致的話(huà),你的庫(kù)/框架不會(huì)有任何出彩的地方。
好的庫(kù)/框架,命名有幾個(gè)原則,***個(gè)原則,就是要有厚重的歷史感。
在80年代,因?yàn)镃語(yǔ)言支持的變量名最長(zhǎng)為8字節(jié),聰明的程序員們使用了一種縮寫(xiě)方式,保留發(fā)音的輕輔音字母,省略元音字母和部分濁輔音字母。
比如:
- button=>btn
- text=>txt
- search=>srch
- fuck=>fk
- click=>clk
- double=>db
沒(méi)錯(cuò),這樣雖然省略了字母,但是英文好的人仍然可以讀出單詞來(lái),而現(xiàn)在,雖然我們完全沒(méi)有這種需要,我們也可以為了給新人以距離感和絕對(duì)的震懾而使用這種命名。
還有一種歷史上的命名方式:匈牙利命名。
匈牙利命名使用簡(jiǎn)寫(xiě)的類(lèi)型作為變量的前綴,比如
- iCount表示int類(lèi)型的count
- szText表示字符串類(lèi)型的text
- bIsNumber表示布爾類(lèi)型isNumber
- dRate表示表示雙精度浮點(diǎn)類(lèi)型rate
是不是看上去很酷?值得一提的是,sz表示以0結(jié)尾的字符串,這是C語(yǔ)言中字符串的實(shí)現(xiàn)方式,JS中完全不是這樣實(shí)現(xiàn)的字符串,所以這樣用可以大大提升你在新手中的地位,他們做夢(mèng)也猜不到sz是字符串的意思。
另外,其實(shí)js是弱類(lèi)型語(yǔ)言,變量根本就跟類(lèi)型不是綁定的。
除了歷史之外,特殊符號(hào)也是我們的***,在javascript中,$美元符號(hào)和_下劃線(xiàn)是非常棒的選擇。這當(dāng)中的代表作當(dāng)屬jQuery和underscore.
jQuery的$使用也并非原創(chuàng),先行者是prototype.js,這也讓jQuery的做法具有相當(dāng)厚重的歷史感。同時(shí),美元符號(hào)比下劃線(xiàn)強(qiáng)的地方是,美元符號(hào)還具有吉祥如意的寓意,咱們寫(xiě)代碼的,出來(lái)不就是混口飯吃,如果代碼經(jīng)常出現(xiàn)美元,一定會(huì)給我們帶來(lái)很多財(cái)運(yùn)的。
占領(lǐng)這些特殊符號(hào)可以讓別的框架無(wú)符號(hào)可用,當(dāng)年jQuery和prototype.js爭(zhēng)霸之時(shí),jQuery就被迫搞出來(lái)了 noconflict——盡管基本沒(méi)見(jiàn)過(guò)有人用過(guò),畢竟要把滿(mǎn)篇的$改成jQuery還是頗費(fèi)體力的,多數(shù)人會(huì)選擇放棄一個(gè)庫(kù)。(什么你說(shuō)根本不需要替換?直接在外面套個(gè)閉包就能解決問(wèn)題?醒醒吧親,能同時(shí)用倆帶$庫(kù)的工程師怎么可能會(huì)那種高級(jí)玩意兒啊,人家都是實(shí)踐派好吧?)
不過(guò)大家不要傷心,雖然沒(méi)有了$和_可以搶?zhuān)珽S5為我們帶來(lái)了更多奇形怪狀的、鍵盤(pán)輕易都輸入不來(lái)的標(biāo)示符可用字符。我首先要推薦的是兩個(gè)零寬字符<zwnj>和<zwj>,這倆字符一個(gè)是連接符,一個(gè)是非連接符,它們的厲害之處在于,不可見(jiàn),通過(guò)這倆字符,你可以制造出假的$來(lái)。
請(qǐng)看以下代碼:
var $ = 1;
估計(jì)你做夢(mèng)也想不到這變量其實(shí)是$\u200D(<zwj>)吧......
通過(guò)\u200D和\u200C的組合,可以制造神奇的代碼出來(lái),你的用戶(hù)一定會(huì)交口稱(chēng)贊你的魔法代碼的!
不止如此!更多奇怪的字符等你挖掘!
接口設(shè)計(jì)
除了命名,接口設(shè)計(jì)也是框架的核心之一。
那些平庸的框架會(huì)用"單一職責(zé)"原則來(lái)設(shè)計(jì)接口:不論是類(lèi)還是函數(shù),一個(gè)只做一件事,而且跟命名 中所說(shuō)的完全一致。
Noooooooooooo ! 這也太無(wú)趣了!
我們來(lái)看看jQuery的$有多少種用法!摘自官方文檔:
- jQuery( selector [, context ] )
- jQuery( element )
- jQuery( elementArray )
- jQuery( object )
- jQuery( jQuery object )
- jQuery()
- jQuery( html [, ownerDocument ] )
- jQuery( html, attributes )
- jQuery( callback )
沒(méi)錯(cuò)!這個(gè)函數(shù)(jQuery就是)居然有9種重載!而且重載中最少包含了3種毫不相干的使用方法!一段時(shí)間里,我曾經(jīng)在面試中問(wèn)所有聲稱(chēng)自己熟悉jQuery的面試者這個(gè)函數(shù)有多少種用法,可以答上三種以上的僅有1人,而沒(méi)有人答出來(lái)過(guò)超過(guò)5種!
可以說(shuō),$在jQuery使用者的眼里就是一個(gè)神!你能想到的事情它都能做!在可以預(yù)見(jiàn)的將來(lái),相信jQuery會(huì)結(jié)合人工智能,做到不論你想實(shí)現(xiàn)任何功能,都只需要寫(xiě)同樣的代碼:
- $();
怎么樣,看清楚接口設(shè)計(jì)的原則了么?那就是:盡量把功能加到以前的接口上,通過(guò)加參數(shù)、區(qū)分參數(shù)類(lèi)型來(lái)添加功能,不論它們有沒(méi)有聯(lián)系,也不論API的名稱(chēng)是什么!哦...... 對(duì)了這個(gè)應(yīng)該結(jié)合上文提到的命名,請(qǐng)使用沒(méi)有任何意義的魔法變量名!
耦合
你可能常常聽(tīng)到一些舊時(shí)代的程序員講,程序必須"高內(nèi)聚、低耦合"。然而,這個(gè)說(shuō)法具有極大的誤導(dǎo)性。
我們先來(lái)看看jQuery的事件綁定:
- var hiddenBox = $( "#banner-message" );
- $( "#button-container button" ).on( "click", function( event ) {
- hiddenBox.show();
- });
- 假如我不想使用選擇器,只想要綁定事件到一個(gè)DOM元素上怎么辦呢?答案是,你要首先把他變成一個(gè)jQuery對(duì)象才行
- $(document.querySelector("#button-container button")).on( "click", function( event ) {
- hiddenBox.show();
- });
接下來(lái)我們來(lái)看jQuery的ajax部分:
- $.ajax({
- url: "/api/getWeather",
- data: {
- zipcode: 97201
- },
- success: function( data ) {
- $( "#weather-temp" ).html( "<strong>" + data + "</strong> degrees" );
- }
- });
假如你僅僅想要使用$.ajax這個(gè)功能,不想使用選擇器等功能怎么辦呢?答案很簡(jiǎn)單:像你需要使用全部功能一樣,在頁(yè)面引用僅有97k的jQuery,然后使用$.ajax。
從這個(gè)例子中我們可以看出,耦合對(duì)于一個(gè)庫(kù)的重要性:耦合讓你那些不太被人接受的功能,跟著受歡迎的功能一起被強(qiáng)制使用,這樣,用戶(hù)就會(huì)逐漸被強(qiáng)奸,逐漸變得認(rèn)為理所當(dāng)然,這正是jQuery能夠成為"事實(shí)標(biāo)準(zhǔn)"的奧秘。
原文鏈接:http://www.cnblogs.com/winter-cn/archive/2013/02/20/2919855.html