读Zepto源码之IOS3模块

IOS3 模块是针对 IOS 的兼容模块,实现了两个经常使用方法的兼容,这两个方法分别是 trimreducejavascript

读 Zepto 源码系列文章已经放到了github上,欢迎star: reading-zeptojava

源码版本

本文阅读的源码为 zepto1.2.0ios

GitBook

reading-zeptogit

trim

if (String.prototype.trim === undefined) // fix for iOS 3.2
  String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, '') }

看注释, trim 是为了兼容 ios3.2 的。github

也是常规的作法,若是 Stringprototype 上没有 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])this

参数

  • 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 能获取到值。

这段还巧妙地用了 ++kk++ 。若是 k 在对象 t 中存在时,则赋值给 accumulatork 再自增,不然用 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

系列文章

  1. 读Zepto源码之代码结构
  2. 读Zepto源码以内部方法
  3. 读Zepto源码之工具函数
  4. 读Zepto源码之神奇的$
  5. 读Zepto源码之集合操做
  6. 读Zepto源码之集合元素查找
  7. 读Zepto源码之操做DOM
  8. 读Zepto源码之样式操做
  9. 读Zepto源码之属性操做
  10. 读Zepto源码之Event模块
  11. 读Zepto源码之IE模块
  12. 读Zepto源码之Callbacks模块
  13. 读Zepto源码之Deferred模块
  14. 读Zepto源码之Ajax模块
  15. 读Zepto源码之Assets模块
  16. 读Zepto源码之Selector模块
  17. 读Zepto源码之Touch模块
  18. 读Zepto源码之Gesture模块

附文

参考

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,全部文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

做者:对角另外一面

相关文章
相关标签/搜索