Zepto 提供了丰富的工具函数,下面来一一解读。

源码版本

本文阅读的源码为 zepto1.2.0

$.extend

$.extend 方法可以用来扩展目标对象的属性。目标对象的同名属性会被源对象的属性覆盖。

$.extend 其实调用的是内部方法 extend, 所以我们先看看内部方法 extend 的具体实现。

function extend(target, source, deep) {
for (key in source) // 遍历源对象的属性值
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { // 如果为深度复制,并且源对象的属性值为纯粹对象或者数组
if (isPlainObject(source[key]) && !isPlainObject(target[key])) // 如果为纯粹对象
target[key] = {} // 如果源对象的属性值为纯粹对象,并且目标对象对应的属性值不为纯粹对象,则将目标对象对应的属性值置为空对象
if (isArray(source[key]) && !isArray(target[key])) // 如果源对象的属性值为数组,并且目标对象对应的属性值不为数组,则将目标对象对应的属性值置为空数组
target[key] = []
extend(target[key], source[key], deep) // 递归调用extend函数
} else if (source[key] !== undefined) target[key] = source[key] // 不对undefined值进行复制
}

extend 的第一个参数 taget 为目标对象, source 为源对象, deep 表示是否为深度复制。当 deeptrue 时为深度复制, false 时为浅复制。

  1. extend 函数用 for···insource 的属性进行遍历

  2. 如果 deepfalse 时,只进行浅复制,将 source 中不为 undefined 的值赋值到 target 对应的属性中(注意,这里用的是 !==,不是 != ,所以只排除严格为 undefined 的值,不包含 null )。如果 source 对应的属性值为对象或者数组,会保持该对象或数组的引用。

  3. 如果 deeptrue ,并且 source 的属性值为纯粹对象或者数组时

    3.1. 如果 source 的属性为纯粹对象,并且 target 对应的属性不为纯粹对象时,将 target 的对应属性设置为空对象

    3.2. 如果 source 的属性为数组,并且 target 对应属性不为数组时,将 target 的对应属性设置为空数组

    3.3. 将 sourcetarget 对应的属性及 deep 作为参数,递归调用 extend 函数,以实现深度复制。

现在,再看看 $.extend 的具体实现

$.extend = function(target) {
var deep, args = slice.call(arguments, 1)
if (typeof target == 'boolean') {
deep = target
target = args.shift()
}
args.forEach(function(arg) { extend(target, arg, deep) })
return target
}

在说原理之前,先来看看 $.extend 的调用方式,调用方式如下:

$.extend(target, [source, [source2, ...]])

$.extend(true, target, [source, ...])

$.extend 中,如果不需要深度复制,第一个参数可以是目标对象 target, 后面可以有多个 source 源对象。如果需要深度复制,第一个参数为 deep ,第二个参数为 target ,为目标对象,后面可以有多个 source 源对象。

$.extend 函数的参数设计得很优雅,不需要深度复制时,可以不用显式地将 deep 置为 false。这是如何做到的呢?

$.extend 函数中,定义了一个数组 args,用来接受除第一个参数外的所有参数。

然后判断第一个参数 target 是否为布尔值,如果为布尔值,表示第一个参数为 deep ,那么第二个才为目标对象,因此需要重新为 target 赋值为 args.shift()

最后就比较简单了,循环源对象数组 args, 分别调用 extend 方法,实现对目标对象的扩展。

$.each

$.each 用来遍历数组或者对象,源码如下:

$.each = function(elements, callback) {
var i, key
if (likeArray(elements)) { // 类数组
for (i = 0; i < elements.length; i++)
if (callback.call(elements[i], i, elements[i]) === false) return elements
} else { // 对象
for (key in elements)
if (callback.call(elements[key], key, elements[key]) === false) return elements
} return elements
}

先来看看调用方式:$.each(collection, function(index, item){ ... })

$.each 接收两个参数,第一个参数 elements 为需要遍历的数组或者对象,第二个 callback 为回调函数。

如果 elements 为数组,用 for 循环,调用 callback ,并且将数组索引 index 和元素值 item 传给回调函数作为参数;如果为对象,用 for···in 遍历属性值,并且将属性 key 及属性值传给回调函数作为参数。

注意回调函数调用了 call 方法,call 的第一个参数为当前元素值或当前属性值,所以回调函数的上下文变成了当前元素值或属性值,也就是说回调函数中的 this 指向的是 item 。这在dom集合的遍历中相当有用。

在遍历的时候,还对回调函数的返回值进行判断,如果回调函数返回 falseif (callback.call(elements[i], i, elements[i]) === false) ) ,立即中断遍历。

$.each 调用结束后,会将遍历的数组或对象( elements )返回。

$.map

可以遍历数组(类数组)或对象中的元素,根据回调函数的返回值,将返回值组成一个新的数组,并将该数组扁平化后返回,会将 nullundefined 排除。

$.map = function(elements, callback) {
var value, values = [],
i, key
if (likeArray(elements))
for (i = 0; i < elements.length; i++) {
value = callback(elements[i], i)
if (value != null) values.push(value)
}
else
for (key in elements) {
value = callback(elements[key], key)
if (value != null) values.push(value)
}
return flatten(values)
}

先来看看调用方式: $.map(collection, function(item, index){ ... })

elements 为类数组或者对象。callback 为回调函数。当为类数组时,用 for 循环,当为对象时,用 for···in 循环。并且将对应的元素(属性值)及索引(属性名)传递给回调函数,如果回调函数的返回值不为 null 或者 undefined ,则将返回值存入新数组中,最后将新数组扁平化后返回。

$.camelCase

该方法是将字符串转换成驼峰式的字符串

$.camelCase = camelize

$.camelCase 调用的是内部方法 camelize ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述,本篇文章就不再展开。

$.contains

用来检查给定的父节点中是否包含有给定的子节点,源码如下:

$.contains = document.documentElement.contains ?
function(parent, node) {
return parent !== node && parent.contains(node)
} :
function(parent, node) {
while (node && (node = node.parentNode))
if (node === parent) return true
return false
}

先来看看调用:$.contains(parent, node)

参数 parent 为父子点,node 为子节点。

$.contains 的主体是一个三元表达式,返回的是一个匿名函数。三元表达式的条件是 document.documentElement.contains, 用来检测浏览器是否支持 contains 方法,如果支持,则直接调用 contains 方法,并且将 parentnode 为同一个元素的情况排除。

否则,返回另一外匿名函数。该函数会一直向上寻找 node 元素的父元素,如果能找到跟 parent 相等的父元素,则返回 true, 否则返回 false

$.grep

该函数其实就是数组的 filter 函数

  $.grep = function(elements, callback) {
return filter.call(elements, callback)
}

从源码中也可以看出,$.grep 调用的就是数组方法 filter

$.inArray

返回指定元素在数组中的索引值

 $.inArray = function(elem, array, i) {
return emptyArray.indexOf.call(array, elem, i)
}

先来看看调用 $.inArray(element, array, [fromIndex])

第一个参数 element 为指定的元素,第二个参数为 array 为数组, 第三个参数 fromIndex 为可选参数,表示从哪个索引值开始向后查找。

$.inArray 其实调用的是数组的 indexOf 方法,所以传递的参数跟 indexOf 方法一致。

$.isArray

判断是否为数组

$.isArray = isArray

$.isArray 调用的是内部方法 isArray ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述。

$.isFunction

判读是否为函数

$.isFunction = isFunction

$.isFunction 调用的是内部方法 isFunction ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述。

$.isNumeric

是否为数值

$.isNumeric = function(val) {
var num = Number(val), // 将参数转换为Number类型
type = typeof val
return val != null &&
type != 'boolean' &&
(type != 'string' || val.length) &&
!isNaN(num) &&
isFinite(num)
|| false
}

判断是否为数值,需要满足以下条件

  1. 不为 null
  2. 不为布尔值
  3. 不为NaN(当传进来的参数不为数值或如'123'这样形式的字符串时,都会转换成NaN)
  4. 为有限数值
  5. 当传进来的参数为字符串的形式,如'123' 时,会用到下面这个条件来确保字符串为数字的形式,而不是如 123abc 这样的形式。(type != 'string' || val.length) && !isNaN(num) 。这个条件的包含逻辑如下:如果为字符串类型,并且为字符串的长度大于零,并且转换成数组后的结果不为NaN,则断定为数值。(因为 Number('') 的值为 0

$.isPlainObject

是否为纯粹对象,即以 {} 常量或 new Object() 创建的对象

$.isPlainObject = isPlainObject

$.isPlainObject 调用的是内部方法 isPlainObject ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述。

$.isWindow

是否为浏览器的 window 对象

$.isWindow = isWindow

$.isWindow 调用的是内部方法 isWindow ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述。

$.noop

空函数

$.noop = function() {}

这个在需要传递回调函数作为参数,但是又不想在回调函数中做任何事情的时候会非常有用,这时,只需要传递一个空函数即可。

$.parseJSON

将标准JSON格式的字符串解释成JSON

if (window.JSON) $.parseJSON = JSON.parse

其实就是调用原生的 JSON.parse, 并且在浏览器不支持的情况下,zepto 还不提供这个方法。

$.trim

删除字符串头尾的空格

$.trim = function(str) {
return str == null ? "" : String.prototype.trim.call(str)
}

如果参数为 null 或者 undefined ,则直接返回空字符串,否则调用字符串原生的 trim 方法去除头尾的空格。

$.type

类型检测

$.type = type

$.type 调用的是内部方法 type ,该方法在前一篇文章《读Zepto源码之内部方法》中已有阐述。

能检测的类型有 "Boolean Number String Function Array Date RegExp Object Error"

系列文章

  1. 读Zepto源码之代码结构
  2. 读 Zepto 源码之内部方法

参考

作者:对角另一面

读 zepto 源码之工具函数的更多相关文章

  1. 读zepto源码之工具函数

    读zepto源码之工具函数 Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目 ...

  2. 读 Zepto 源码之神奇的 $

    经过前面三章的铺垫,这篇终于写到了戏肉.在用 zepto 时,肯定离不开这个神奇的 $ 符号,这篇文章将会看看 zepto 是如何实现 $ 的. 读Zepto源码系列文章已经放到了github上,欢迎 ...

  3. 读Zepto源码之集合操作

    接下来几个篇章,都会解读 zepto 中的跟 dom 相关的方法,也即源码 $.fn 对象中的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码 ...

  4. 读 Zepto 源码之集合元素查找

    这篇依然是跟 dom 相关的方法,侧重点是跟集合元素查找相关的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zept ...

  5. 读Zepto源码之操作DOM

    这篇依然是跟 dom 相关的方法,侧重点是操作 dom 的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1 ...

  6. 读Zepto源码之样式操作

    这篇依然是跟 dom 相关的方法,侧重点是操作样式的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1.2. ...

  7. 读Zepto源码之属性操作

    这篇依然是跟 dom 相关的方法,侧重点是操作属性的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1.2. ...

  8. 读Zepto源码之Event模块

    Event 模块是 Zepto 必备的模块之一,由于对 Event Api 不太熟,Event 对象也比较复杂,所以乍一看 Event 模块的源码,有点懵,细看下去,其实也不太复杂. 读Zepto源码 ...

  9. 读Zepto源码之Callbacks模块

    Callbacks 模块并不是必备的模块,其作用是管理回调函数,为 Defferred 模块提供支持,Defferred 模块又为 Ajax 模块的 promise 风格提供支持,接下来很快就会分析到 ...

随机推荐

  1. iOS回顾笔记(07) -- UITableView的使用和性能优化

    iOS回顾笔记(07) -- UITableView的使用和性能优化 如果问iOS中最重要的最常用的UI控件是什么,我觉得UITableView当之无愧!似乎所有常规APP都使用到了UITableVi ...

  2. QT Creator 快速入门教程 读书笔记(二)

    一 窗口部件 基础窗口部件QWidget类是所有用户界面对象的基类,窗口和控件都是直接或间接继承自 QWidget,下面我们来看一个很简单的例子: 窗口部件(Widget)简称部件,是QT中建立界面的 ...

  3. 老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

    上篇中,我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理,编译和部署镜像,并且设置容器的自动启动.但是,还有一些重要的问题没有解决,这些问题不解决,就完 ...

  4. 用excel.php类库导出excel文件

    excel.php是个小型的php类库,可以满足基本的从数据库中取出数据然后导出xls格式的excel文件,代码如下: 1 class Excel { 2 public $filename = 'ex ...

  5. iOS开发之Quartz2D

    1.         Quartz2D概述及作用 Quartz2D的API是纯C语言的,Quartz2D的API来自于Core Graphics框架. 数据类型和函数基本都以CG作为前缀,比如: CG ...

  6. IT生涯, 我的常用软件清单

    IT生涯, 我的常用软件清单 SkySeraph Jan. 26th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.skysera ...

  7. jqzoom插件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...

  8. 服务器证书安装配置指南(SLB)

    一.生成证书请求  1.下载CSR生成工具 您需要使用CSR生成工具来创建证书请求.  下载AutoCSR: http://www.itrus.cn/soft/autocsr.rar  2.生成服务器 ...

  9. Legendary Items-微软实习生笔试第一题

    题目如下: 这道题难点不仅在于正确理解题意,判断递归条件,更在于用数学方法推出解决公式.因为N最大为1百万,而内存只有256MB, 所以暴力递归肯定会超时,超空间. 不过,我才疏学浅,又没有大量时间去 ...

  10. centos 6.5 搭建ftp服务器

    linux下一般使用vsftpd作为ftp服务器. vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序.特点是小巧轻快,安全易用. 下面是安装配置步骤: 1.安装vsftpd yum i ...