读zepto核心源码学习JS笔记(2)--工具函数

1. $.type $.isArray $.isFunction $.isNumeric $.isPlainObject $.isWindow

  • 判断对象的方法介绍
    在zepto源码中,使用了Object.prototype.toString.call()方法判断对象的类型,以下简单介绍下此方法的大致情况
//null
Object.prototype.toString.call(null);//”[object Null]”
//undefined
Object.prototype.toString.call(undefined);//”[object Undefined]”
//string
Object.prototype.toString.call(“aaa”);//”[object String]”
//number
Object.prototype.toString.call(111);//”[object Number]”
//boolean
Object.prototype.toString.call(true);//”[object Boolean]”
//函数
Function fn(){console.log(“xixi”);}
Object.prototype.toString.call(fn);//”[object Function]”
//数组类型
var arr = [1,2,,3,4];
Object.prototype.toString.call(arr);//”[object Array]”
//日期
var date = new Date();
Object.prototype.toString.call(date);//”[object Date]”
//自定义类型
//不能判断aa是不是AA的实例,要用instanceof判断
function AA(a, b) {
    this.a = a;
    this.b = b;
}
var aa = new AA("xixi", 'haha');
Object.prototype.toString.call(aa); //”[object Object]”
Object.prototype.toString.call(aa); //”[object Object]”
//正则
var aa = /^\w$/
Object.prototype.toString.call(aa); //”[object RegExp]”
  • 在zepto中,先定义了一个空对象class2type,并取出对象函数自带的toString方法,即为Object.prototype.toString.call()
class2type = {},
toString = class2type.toString,

然后填充class2type的值;

$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type["[object " + name + "]"] = name.toLowerCase()
    //最终结果
    //class2type[”[object Boolean]”] = boolean,
    //class2type[”[object Number]”] = number,
    //class2type[”[object String]”] = string,
    // ...
  })
  • 准备工作做完,就可以进行对象的判断了;

    • 首先封装一个判断方法,根据这个方法的返回值来判断对象的类型;
    //比如,如果要判断function aa(){};则返回class2type[Object.prototype.toString.call(aa)]==class2type[”[object Function]”]==function;所以就判断出为函数
    function type(obj) {
     //如果obj为null或者undefined,返回字符串'null','undefined';否则返回class2type[]或者object
          return obj == null ? String(obj) :class2type[toString.call(obj)] || "object"
    }
    
    $.type = type
    
    • 下面根据上面的封装方法返回值判断类型;

      • 判断函数
      function isFunction(value) {
          return type(value) == "function"
        }
      
      $.isFunction = isFunction
      
      • 判断window;根据widow自己的属性来判断;window.window = window;
      function isWindow(obj) {
          return obj != null && obj == obj.window
        }
      
      $.isWindow = isWindow
      
      • 判断document
      function isDocument(obj) {
          return obj != null && obj.nodeType == obj.DOCUMENT_NODE
        }
      
      • 判断是否为对象
      function isObject(obj) {
          return type(obj) == "object"
        }
      
      • 对于通过字面量定义的对象和new Object的对象返回true,new Object时传参数的返回false
      function isPlainObject(obj) {
          return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype
        }
      
      $.isPlainObject = isPlainObject
      
      • 判断数组
      function isArray(value) {
          return value instanceof Array
        }
      
      $.isArray = isArray
      
      • 判断类数组
      function likeArray(obj) {
          return typeof obj.length == 'number'
        }
      
      • 空对象
      $.isEmptyObject = function(obj) {
          var name
          for (name in obj) return false
          return true
        }
      
      • 有限数值或者字符串表达的数字
      $.isNumeric = function(val) {
          var num = Number(val), type = typeof val
          return val != null && type != 'boolean' &&
            (type != 'string' || val.length) &&
            !isNaN(num) && isFinite(num) || false
        }
      

2. $.camelCase

camelize = function(str){ 
    return str.replace(/-+(.)?/g,
        function(match, chr){ return chr ? chr.toUpperCase() : '' }
    ) 
}
$.camelCase = camelize
  • 用法

    $.camelCase('hello-there') //=> "helloThere"
    $.camelCase('helloThere')  //=> "helloThere"
    
  • str.replcace(a,b)

    将str中的a替换成b;上面代码中将b用了函数返回值来表达;

3. $.contain

//为了判断某个节点是不是另一个节点的后代,浏览器引入了contains()方法;
$.contains = document.documentElement.contains ?
//如果浏览器支持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
}
  • 检查父节点是否包含给定的dom节点,如果两者是相同的节点,则返回false

4. $.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
}
  • 遍历,将每次循环的值作为callback的上下文;如果callback返回的结果为false,遍历停止;

5. $.extend

function extend(target, source, deep) {
    for (key in source)
    //如果是神拷贝,source[key]是对象或者数组
      if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
      //source[key]是对象,而target[key]不是对象
        if (isPlainObject(source[key]) && !isPlainObject(target[key]))
          target[key] = {}
      //source[key]是数组,而target[key]不是数组
        if (isArray(source[key]) && !isArray(target[key]))
          target[key] = []
          //递归
        extend(target[key], source[key], deep)
      }
      else if (source[key] !== undefined) target[key] = source[key]
  }
$.extend = function(target){
    var deep, args = slice.call(arguments, 1)
    //如果传入的第一个参数为布尔值
    if (typeof target == 'boolean') {
      deep = target
     //将除第一个参数外的参数赋值给target
      target = args.shift()
    }
    //遍历参数,将参数都复制到target上;
    args.forEach(function(arg){ extend(target, arg, deep) })
    return target
  }
  • 我们首先看一下用法;
$.extend(target, [source, [source2, ...]])   ⇒ target
$.extend(true, target, [source, ...])   ⇒ target v1.0+
var target = { one: 'patridge' },
source = { two: 'turtle doves' }
$.extend(target, source)//{one: "patridge", two: "turtle doves"}
  • target代表被拓展的对象,source为源对象;deep代表是深复制还是浅复制;

    • 对于字符串来说,浅复制是对值的复制,,对于对象来说,浅复制是对对象地址的复制,两者共同指向同一个地址,其中一个改变,另一个对象也会随之改变,而深复制是在堆区中开辟一个新的,两个对象则指向不同的地址,相互独立;
  • slice.call(arguments, 1)选取传入参数的第一个参数到最后一个参数;

5. $.inArray

$.inArray = function(elem, array, i){
    return emptyArray.indexOf.call(array, elem, i)
}
  • 用法
$.inArray("abc",["bcd","abc","edf","aaa"]);//=>1
$.inArray("abc",["bcd","abc","edf","aaa"],1);//=>1
$.inArray("abc",["bcd","abc","edf","aaa"],2);//=>-1
  • 返回数组中指定元素的索引值,如果没有找到该元素则返回-1。

6. $.map

$.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)
 }
  • element为类数组对象或者对象;

    • 如果为类数组对象的话,用for循环
    • 如果为对象的话,用fo.....in....循环
    • 再将索引和值传给callback,
    • 如果callback的返回值不是null或者undefined,存入新的数组
    • 最后将数组扁平化flatten()---数组降维,二维数组转为一维数组
  • flatten()

    function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }

    这里巧妙应用了apply方法,apply方法的第一个元素会被当作this,第二个元素被做为传入的参数arguments;
    例如:concat.apply([],[[1],[2],[3]]),等价于[].concat([1],[2],[3]),输出的值为[1,2,3],就实现了数组的扁平化;

7. $.noop

$.noop = function() {}
  • 引用空函数

8. $.parseJSON

if (window.JSON) $.parseJSON = JSON.parse
  • 原生JSON.parse的别名;接受一个JSON字符串,返回解析后的javascript对象。

9. $.trim

$.trim = function(str) {
    return str == null ? "" : String.prototype.trim.call(str)
}
  • 去除字符串开头和结尾的空格
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,703评论 2 17
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,045评论 1 10
  • 三、闭包和高阶函数 3.1 闭包 3.1.1 变量的作用域 所谓变量的作用域,就是变量的有效范围。通过作用域的划分...
    梁同学de自言自语阅读 1,440评论 0 6
  • 第一次听到母亲哭泣是1998年,那一年我上二年级,面对三个上门的村干部催缴集资,母亲手里拿不出钱,急得团团转......
    阿土127阅读 385评论 0 4
  • 世界上的事啊,真奇怪,真真假假,挺让人觉得唏嘘。——大栗致自己 这两天,我学习了如何排版和剪辑视频。没学之前,总给...
    有杕之杜阅读 469评论 1 3