IOS3
模組是針對 IOS
的相容模組,實現了兩個常用方法的相容,這兩個方法分別是 trim
和 reduce
。
讀 Zepto 原始碼系列文章已經放到了github上,歡迎star: reading-zepto
原始碼版本
本文閱讀的原始碼為 zepto1.2.0
GitBook
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
作為引數傳遞給回撥函式,直至陣列耗盡,然後將結果返回。
系列文章
系列文章
- 讀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模組
附文
參考
License
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最後,所有文章都會同步傳送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面