IOS3
模塊是針對 IOS
的兼容模塊,實現了兩個常用方法的兼容,這兩個方法分別是 trim
和 reduce
。
讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-zepto
源碼版本
本文閱讀的源碼為 zepto1.2.0
GitBook
《reading-zepto》
trim
if (String.prototype.trim === undefined) // fix for iOS 3.2
String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, '') }
看註釋, trim
是為了兼容 ios3.2
的。
也是常規的做法,如果 String
的 prototype
上沒有 trim
方法,則自己實現一個。
實現的方式也簡單,就是用正則將開頭和結尾的空格去掉。^\s+
這段是匹配開頭的空格,\s+$
是匹配結尾的空格。
reduce
// For iOS 3.x
// from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
if (Array.prototype.reduce === undefined)
Array.prototype.reduce = function(fun){
if(this === void 0 || this === null) throw new TypeError()
var t = Object(this), len = t.length >>> 0, k = 0, accumulator
if(typeof fun != 'function') throw new TypeError()
if(len == 0 && arguments.length == 1) throw new TypeError()
if(arguments.length >= 2)
accumulator = arguments[1]
else
do{
if(k in t){
accumulator = t[k++]
break
}
if(++k >= len) throw new TypeError()
} while (true)
while (k < len){
if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t)
k++
}
return accumulator
}
用法與參數
要理解這段代碼,先來看一下 reduce
的用法和參數:
用法:
arr.reduce(callback[, initialValue])
參數:
- callback: 回調函數,有如下參數
- accumulator: 上一個回調函數返回的值或者是初始值(
initialValue
) - currentValue: 當前值
- currentIndex: 當前值在數組中的索引
- array: 調用
reduce
的數組 - initialValue: 初始值,如果沒有提供,則為數組的第一項。如果數組為空數組,而又沒有提供初始值時,會報錯
檢測參數
if(this === void 0 || this === null) throw new TypeError()
var t = Object(this), len = t.length >>> 0, k = 0, accumulator
if(typeof fun != 'function') throw new TypeError()
if(len == 0 && arguments.length == 1) throw new TypeError()
首先檢測是否為 undefined
或者 null
,如果是,則報類型錯誤。這裏有一點值得註意的,判斷是否為 undefined
時,用了 void 0
的返回值,因為 void
操作符返回的結果都為 undefined
,這是為了避免 undefined
被重新賦值,出現誤判的情況。
接下來,將數組轉換成對象,用變量 t
來保存,後面會看到,遍歷用的是 for...in
來處理。為什麽不直接用 for
來處理數組呢?因為 reduce
不會處理稀疏數組,所以轉換要轉換成對象來處理。
數組長度用 len
來保存,這裏使用了無符號位右移操作符 >>>
,確保 len
為非負整數。
用 k
來保存當前索引,accumulator
為返回值。
接下來,檢測回調函數 fun
是否為 function
,如果不是,拋出類型錯誤。
在數組為空,並且又沒有提供初始值(即只有一個參數 fun
)時,拋出類型錯誤。
accumulator初始值
if(arguments.length >= 2)
accumulator = arguments[1]
else
do{
if(k in t){
accumulator = t[k++]
break
}
if(++k >= len) throw new TypeError()
} while (true)
如果參數至少有兩項,則 accumulator
的初始值很簡單,就是 arguments[1]
,即 initialValue
。
如果沒有提供初始值,則叠代索引,直到找到在對象 t
中存在的索引。註意這裏用了 do...while
,所以最終結果,要麽是報類型錯誤,要麽 accumulator
能獲取到值。
這段還巧妙地用了 ++k
和 k++
。如果 k
在對象 t
中存在時,則賦值給 accumulator
後 k
再自增,否則用 k
自增後再和 len
比較,如果超出 len
的長度,則報錯,因為不存在下一個可以賦給 accumulator
的值。
返回結果
while (k < len){
if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t)
k++
}
return accumulator
要註意,如果沒有提供初始值時,k
是自增後的值,即不再需要處理數組的第一個值。
到這裏問題就比較簡單了,就是 while
循環,用 accumulator
保存回調函數返回的值,在下一次循環時,再將 accumulator
作為參數傳遞給回調函數,直至數組耗盡,然後將結果返回。
系列文章
《reading-zepto》
系列文章
- 讀Zepto源碼之代碼結構
- 讀Zepto源碼之內部方法
- 讀Zepto源碼之工具函數
- 讀Zepto源碼之神奇的$
- 讀Zepto源碼之集合操作
- 讀Zepto源碼之集合元素查找
- 讀Zepto源碼之操作DOM
- 讀Zepto源碼之樣式操作
- 讀Zepto源碼之屬性操作
- 讀Zepto源碼之Event模塊
- 讀Zepto源碼之IE模塊
- 讀Zepto源碼之Callbacks模塊
- 讀Zepto源碼之Deferred模塊
- 讀Zepto源碼之Ajax模塊
- 讀Zepto源碼之Assets模塊
- 讀Zepto源碼之Selector模塊
- 讀Zepto源碼之Touch模塊
- 讀Zepto源碼之Gesture模塊
附文
- 譯:怎樣處理 Safari 移動端對圖片資源的限制
參考
- Array.prototype.reduce()
License
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
作者:對角另一面
Tags: prototype reduce 源碼 trim 空格 accumulator
文章來源: