讀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)
}
  • 去除字符串開頭和結尾的空格
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 工廠模式類似于現實生活中的工廠可以產生大量相似的商品,去做同樣的事情,實現同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,842評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創建,需要時才創建 最常見的單例模式,...
    Obeing閱讀 2,104評論 1 10
  • 三、閉包和高階函數 3.1 閉包 3.1.1 變量的作用域 所謂變量的作用域,就是變量的有效范圍。通過作用域的劃分...
    梁同學de自言自語閱讀 1,494評論 0 6
  • 第一次聽到母親哭泣是1998年,那一年我上二年級,面對三個上門的村干部催繳集資,母親手里拿不出錢,急得團團轉......
    阿土127閱讀 422評論 0 4
  • 世界上的事啊,真奇怪,真真假假,挺讓人覺得唏噓。——大栗致自己 這兩天,我學習了如何排版和剪輯視頻。沒學之前,總給...
    有杕之杜閱讀 514評論 1 3