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的數組
- accumulator: 上一個回調函數返回的值或者是初始值(
- 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)
最後,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面