读Zepto源码之IOS3模块

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

读 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 的。

也是常规的做法,如果 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])

参数

  • 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)

作者:对角另一面

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逆向技术

框架原理第三讲,RTTCreate,运行时类型创建.(以MFC框架讲解)

       框架原理第三讲,RTTCreate,运行时类型创建.(以MFC框架讲解) 通过昨天的讲解,我们已经理解了运行时类型识别是什么. 比如  CObje...

2046
来自专栏Java 源码分析

Bootstrap 源码分析

Netty 源码分析: Bootstrap 1. 结构 先看一个这个类的类层次结构, ? 好,这个结构还是比较明晰的,然后看他的主要字段,因为这些字段比较重...

2725
来自专栏玄魂工作室

Python黑帽编程2.7 异常处理

异常是个很宽泛的概念,如果程序没有按预想的执行,都可以说是异常了。遇到一些特殊情况没处理会引发异常,比如读文件的时候文件不存在,网络连接超时。程序本身的错误也可...

2889
来自专栏青玉伏案

iOS开发之Runtime常用示例总结

经常有小伙伴私下在Q上问一些关于Runtime的东西,问我有没有Runtime的相关博客,之前还真没正儿八经的总结过。之前只是在解析第三方框架源码时,聊过一些用...

1949
来自专栏python爬虫日记

转载、Python的编码处理(二)

然后,大多数人的做法是,调用encode/decode进行调试,并没有明确思考为何出现乱码

692
来自专栏散尽浮华

shell脚本之特殊符号总结性梳理

# 井号 (comments) 这几乎是个满场都有的符号 #!/bin/bash 井号也常出现在一行的开头,或者位于完整指令之后,这类情况表示符号后面的是注...

18510
来自专栏前端侠2.0

co yield避免嵌套详细代码示例。

991
来自专栏DOTNET

asp.net web api 异常捕获

1 向客户端发送错误消息 使用throw new HttpResponseException()向客户端抛出错误信息。 HttpResponseExceptio...

48712
来自专栏IT可乐

Spring详解(三)------DI依赖注入

  上一篇博客我们主要讲解了IOC控制反转,也就是说IOC 让程序员不在关注怎么去创建对象,而是关注与对象创建之后的操作,把对象的创建、初始化、销毁等工作交给s...

1925
来自专栏北京马哥教育

搞定Linux Shell文本处理工具,看完这篇集锦就够了

Linux Shell是一种基本功,由于怪异的语法加之较差的可读性,通常被Python等脚本代替。既然是基本功,那就需要掌握,毕竟学习Shell脚本的过程中,还...

1582

扫码关注云+社区