mirahs 2019-06-25
IOS3
模块是针对 IOS
的兼容模块,实现了两个常用方法的兼容,这两个方法分别是 trim
和 reduce
。
读 Zepto 源码系列文章已经放到了github上,欢迎star: reading-zepto
本文阅读的源码为 zepto1.2.0
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+$
是匹配结尾的空格。
// 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: 回调函数,有如下参数
initialValue
)reduce
的数组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
)时,抛出类型错误。
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
作为参数传递给回调函数,直至数组耗尽,然后将结果返回。
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面