1. 程式人生 > >ExtJs原始碼學習之namespace和urlEncode

ExtJs原始碼學習之namespace和urlEncode

[size=medium]
真的很慚愧,花了一個半小時才讀完兩個函式, 虧得我還是挑了較簡單的來看。有兩個原因。第一個肯定是自己的基礎不紮實。說實話,我的js功底的確不怎麼好, 只知道用一些常用的函式來實現一些普通的功能。對於那些自己不怎麼用的函式看都不想看一下。讀了幾個函式的程式碼後才發現,不這那些函式不常用,而是已經被人家封裝成更常用的了。都是著了浮躁的道, 痛定思過, 一定要改。 第二個原因,編寫ext的那些大牛們實在是太牛了, 太惜行如金了,大量使用了 ||、&&和三目運算子,人家需要十幾行的程式碼大牛們一行搞定。結果程式碼是緊湊了,但可讀性就低了。比如這句:buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val)) : '');

不多發表感慨了,總結一下今天的閱讀收穫。

先是Ext.namespace()的原始碼, 對於這個函式的用法就不說了, 不清楚的可以去查文件,在Ext類中。


namespace : function(){
var o, d;
Ext.each(arguments, function(v) {
d = v.split(".");
o = window[d[0]] = window[d[0]] || {};
Ext.each(d.slice(1), function(v2){
o = o[v2] = o[v2] || {};
});
});
return o;
}

第一個難點在 o = window[d[0]] = window[d[0]] || {}; 這句上面. 首先執行 window[d[0]] || {}; 若window[d[0]]為空或undefined, 返回{},否則返回window[d[0]]; 然後執行window[d[0]]= . 這個window[val]看起來有點難理解. 其實它的意思是給window物件名為val的屬性賦值, 再說白了就是建立一個名為val的變數. 例如window['abc']='abc'的效果和 var abc='abc'; 相同. (若想知道為什麼, 可以去W3CSchool看看windows物件的說明). 最後執行o=window[d[0]].
我遇到的第二個坑是在slice函式上。剛看見它時怎麼看怎麼陌生,查了W3CSchool才知道它是陣列物件的一個函式:arrOjb.slice(start,end),效果類似於字串的substring().汗顏!再感慨一下: 基礎不牢啊!

這個函式的返回值不是建立的所有物件,而後建立最後一個物件。如Ext.namespace("a","b","c.d.e");返回的是物件e。

然後是Ext.urlEncode。挑它不是因為它常用, 而是因為它看起來好欺負。

urlEncode : function(o, pre){
var empty,
buf = [],
e = encodeURIComponent;

Ext.iterate(o, function(key, item){
//alert("key="+key+",item="+item);
empty = Ext.isEmpty(item);
Ext.each(empty ? key : item, function(val){
buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val))

: '');
});
});
if(!pre){
buf.shift();
pre = '';
}
return pre + buf.join('');
}



這段程式碼對我來說有三道坎。第一道坎是e = encodeURIComponent; 這個是小坎, 查查文件就明白了:‘encodeURI() 函式可把字串作為 URI 進行編碼。如果 URI 元件中含有分隔符,比如 ? 和 #,則應當使用 encodeURIComponent() 方法分別對各元件進行編碼。’ 將encodeURIComponent賦給e純粹是為了使用方便。
第二道坎是

Ext.iterate(o, function(key, item){
empty = Ext.isEmpty(item);
Ext.each(empty ? key : item, function(val){
buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val))

: '');
});
});


沒錯, 這一大段程式碼一開始都沒讀懂。文件中的函式說明是‘Takes an object and converts it to an encoded URL. e.g. Ext.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.’, 意思是說這個函式可以處理json物件,也可以處理陣列。當引數為json物件時,這個函式的執行過程很容易理解,但當引數為陣列時就不那麼直接了. 直到我加入上面那句alert後才有點明白:Ext.iterate在處理陣列物件如["a","b"]時,會把它當作json物件{a:0,b:1}來看.
至於buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val)) : '');這一句有點太長了.可以拆分為buf.push('&', e(key), '=')和buf.push((!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val)); 那麼最難理解的就是!Ext.isEmpty(val) && (val != key || !empty)這個判斷了. 到現在都沒想明白val != key || !empty這個條件會在什麼情況下起作用,即,val在什麼情況下會等於key? 難道會出現傳入{...,undefined:undefinde,...}或{...,null=null,...}這種兩種引數的情況? 如果沒有傳入這兩怪異的引數的話, (!Ext.isEmpty(val) && (val != key || !empty))就可以簡化為!Ext.isEmpty(val)了,剩下的也好理解了.
第三個坎是buf.shif()這個函式:arrayObject.shift()方法用於把陣列的第一個元素從其中刪除,並返回第一個元素的值。
ps:遇到的坎越多,只要不被嚇倒, 收穫就越大.
昨天本來還看了Ext.extend的原始碼, 不過硬是被打擊了.
[/size]