上次看zepto的init方法時,有一段屬性設置的代碼,先來看看其表現:
if (isPlainObject(properties)) { nodes = $(dom) $.each(properties, function(key, value) { if (methodAttributes.indexOf(key) > -1) nodes[key](value) else nodes.attr(key, value) }) }
在分析這里的時候,一直很困惑,為什么實例化dom之后,對nodes進行屬性設置會導致dom也有了屬性設置的結果。回想了一下,在javascript中,對象是引用,而不是賦值,而dom不是zepto對象就是Dom對象,假如是zepto對象的話,那么nodes其實就是dom,因為在zepto的init方法中,傳入參數是zepto對象的話則直接返回該對象。而如果是其他對象的話,則將其設置為數組的第一個元素返回該數組。
zepto.init = function(selector, context) { var dom ... else if (typeof selector == 'string') { ... } ... else if (zepto.isZ(selector)) return selector else { ... else if (isObject(selector)) dom = [selector], selector = null .... } // create a new Zepto collection from the nodes found return zepto.Z(dom, selector) }
那么dom = [selector],是不是相當於dom[0] = selector;也是一個引用呢?

實驗結果也就是一個引用。
那么言歸正傳,我們接下來看$.each函數
$.each = function(elements, callback){ var i, key if (likeArray(elements)) { for (i = 0; i < elements.length; i++) if (callback.call(elements[i], i, elements[i]) === false) return elements } else { for (key in elements) if (callback.call(elements[key], key, elements[key]) === false) return elements } return elements }
該函數事實上並沒有什么特別,對於傳入的第一個參數為要迭代的數組或對象,第二個為回調函數,如果迭代過程中有一個元素或屬性返回false,則返回傳入的第一個參數,否則迭代完再返回第一個參數。
然后就是attr方法了。
attr: function(name, value){ var result return (typeof name == 'string' && !(1 in arguments)) ? (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : this.each(function(idx){ if (this.nodeType !== 1) return if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) }) },
該方法首先判斷傳入的第一個參數是否為一個字符串,並判斷是否有第二個參數,然后根據條件返回讀取屬性的值。
如果傳入的是其他情況,則調用each方法,注意,這里的each是$.fn.each,與上面的$.each不同。
each: function(callback){ emptyArray.every.call(this, function(el, idx){ return callback.call(el, idx, el) !== false }) return this },
each方法傳入一個回調函數,並調用數組的every方法對this(則zepto對象)進行迭代,並將對象的屬性作為回調函數的上下文進行調用。
那么attr方法中,傳入的回調函數,則是首先判斷this的nodeType是否為1,nodeType可以參考這里nodeType。若是,則調用setAttribute方法直接將傳入的key-value對象設置為屬性,否則就通過一個funcArg函數來設置其屬性name的值。
function funcArg(context, arg, idx, payload) { return isFunction(arg) ? arg.call(context, idx, payload) : arg }
