读 zepto 源码之东西函数

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 源码之东西函数》

作者:对角另一面

    原文作者:对角另一面
    原文地址: https://segmentfault.com/a/1190000009244987
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞