這些Zepto中實(shí)用的方法集

前言

時(shí)間過(guò)得可真快,轉(zhuǎn)眼間2017年已去大半有余,你就說(shuō)嚇不嚇人,這一年你成長(zhǎng)了多少,是否荒度了很多時(shí)光,亦或者天天向上,收獲滿(mǎn)滿(mǎn)。今天主要寫(xiě)一些看?Zepto基礎(chǔ)模塊時(shí),比較實(shí)用的部分內(nèi)部方法,在我們?nèi)粘9ぷ骰蛘邔W(xué)習(xí)中也會(huì)用的到。

源碼倉(cāng)庫(kù)
原文鏈接

1. 將數(shù)組鋪平(flatten)

?面試或者工作中經(jīng)常遇到要將多維數(shù)組鋪平成一維數(shù)組。例如將[1, 2, [3], [4], [5]]最后變成[1, 2, 3, 4, 5]

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

這里先將$.fn.concat理解成原生數(shù)組的concat方法,我們會(huì)發(fā)現(xiàn),其實(shí)他只能鋪平一層。例如

[1, 2, [3], [4, [5]]] => [1, 2, 3, 4, [5]]

那怎樣才能將多層嵌套的數(shù)組完全鋪平為一層呢?這里介紹兩種方式。

方式1


let flatten = (array) => {
  return array.reduce((result, val) => {
    return result.concat(Array.isArray(val) ? flatten(val) : val)
  }, [])
}


測(cè)試

let testArr1 = [1, 2, 3, 4]
let testArr2 = [1, [2], 3, [4, [5, [6, [7]]]]]

console.log(flatten(testArr1)) // => [1, 2, 3, 4]
console.log(flatten(testArr2)) // => [1, 2, 3, 4, 5, 6, 7]

方式2


let flatten = (array) => {
  let result = []
  let idx = 0

  array.forEach((val, i) => {
    if (Array.isArray(val)) {
      let value = flatten(val)
      let len = value.length
      let j = 0
      result.length += len

      while ( j < len) {
        result[idx++] = value[j++]
      }
    } else {
      result[idx++] = val
    }
  })

  return result
}

同樣和上面得到的結(jié)果一致

2. 數(shù)組去重(uniq)

數(shù)組去重可謂是老生常談的話(huà)題了,方式有非常多。好久之前寫(xiě)過(guò)一篇關(guān)于去重的文章,歡迎查看。

let uniq = function (array) {
  return filter.call(array, function (item, idx) {
    return array.indexOf(item) == idx
  })
}

結(jié)合數(shù)組的filter方法,查看數(shù)組的某項(xiàng)出現(xiàn)的索引是不是與idx相等,不相等,肯定出現(xiàn)過(guò)2次以上,即將其過(guò)濾掉。其實(shí)結(jié)合es6中的Set數(shù)據(jù)結(jié)構(gòu),可以很方便的做到數(shù)組去重。

let uniq = (array) => {
  return  [...new Set(array)]
}

測(cè)試


let testArr = [1, 1, 2, 3, 0, -1, -1]
console.log(uniq(testArr)) // => [1, 2, 3, 0, -1]

?

3. 連字符轉(zhuǎn)駝峰(camelize)

這個(gè)方法挺實(shí)用的,可以將a-b-c這種形式轉(zhuǎn)換成aBC,當(dāng)然下劃線(xiàn)的?數(shù)量可以是多個(gè),a---b-----c => aBC


let camelize = function (str) {
  return str.replace(/-+(.)?/g, function (match, chr) {
    return chr ? chr.toUpperCase() : ''
  })
}

4. 判斷是否為document對(duì)象(isDocument)。

通過(guò)dom元素的nodeType屬性可以知道其屬于哪種元素類(lèi)型。結(jié)合下面這張表(developer.mozilla.org/en-US/docs/Web/API/Node/nodeType),其實(shí)不僅僅可以寫(xiě)出判斷是否為document對(duì)象,還可以判斷是否為元素對(duì)象等。


function isDocument (obj) {
  return obj != null && obj.nodeType == obj.DOCUMENT_NODE
}

5. 判斷obj是否為類(lèi)數(shù)組(likeArray)

什么是?類(lèi)數(shù)組對(duì)象呢?

類(lèi)數(shù)組對(duì)象:

  1. 含有指向?qū)ο笤氐臄?shù)字索引下標(biāo)以及l(fā)ength屬性標(biāo)志屬性的個(gè)數(shù)
  2. 不含有數(shù)組的push、concat等方法

常見(jiàn)的類(lèi)數(shù)組對(duì)象有auguments,document.getElementsByClassName等api獲取的dom集合,符合上述條件的對(duì)象等。


function likeArray(obj) {
  // !!obj 直接過(guò)濾掉了false,null,undefined,''等值
  // 然后obj必須包含length屬性
  var length = !!obj && 'length' in obj && obj.length,
  // 獲取obj的數(shù)據(jù)類(lèi)型
    type = $.type(obj)
  // 不能是function類(lèi)型,不能是window
  // 如果是array則直接返回true
  // 或者當(dāng)length的數(shù)據(jù)類(lèi)型是number,并且其取值范圍是0到(length - 1)這里是通過(guò)判斷l(xiāng)ength - 1 是否為obj的屬性
  return 'function' != type && !isWindow(obj) && (
    'array' == type || length === 0 ||
    (typeof length == 'number' && length > 0 && (length - 1) in obj)
  )
}

代碼上了注釋?zhuān)饕覀儊?lái)對(duì)比一下underscore中是如何判斷是否為類(lèi)數(shù)組的。

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

underscore中判斷類(lèi)數(shù)組比較寬松一些,MAX_ARRAY_INDEX是JavaScript 中能精確表示的最大數(shù)字,主要判斷對(duì)象的length屬性是否為數(shù)字類(lèi)型,并且是否大于0且在MAX_ARRAY_INDEX范圍內(nèi)。

zepto中類(lèi)數(shù)組判斷就比較嚴(yán)格了,因?yàn)閣indow和函數(shù)其實(shí)都有l(wèi)ength屬性,這里把他們給過(guò)濾掉了。

6. 判斷是否為window對(duì)象

window對(duì)象的window屬性指向其本身,我們來(lái)直接看下mdn上的解釋。


function isWindow (obj) {
  return obj != null && obj == obj.window
}

但實(shí)際上下面的代碼也會(huì)被認(rèn)為是window對(duì)象。

let a = {}
a.window = a

a === a.window // true
isWindow(a) // true

7. 判斷?數(shù)據(jù)類(lèi)型

利用Object.prototype.toString方法來(lái)做數(shù)據(jù)類(lèi)型的判斷。

let class2type = {}
let toString = class2type.toString

  // Populate the class2type map
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
  class2type["[object " + name + "]"] = name.toLowerCase()
})

最后class2type會(huì)變成

class2type = {
  "[object Boolean]": "boolean",
  "[object Array]": "array",
  "[object Number]": "number"
  ...
} 

接著就是type函數(shù)的定義了


function type(obj) {
  return obj == null ? String(obj) :
  class2type[toString.call(obj)] || "object"
}

首先如果傳入的obj是null或者undefined,則用String函數(shù)返貨null或者undefined,而toString.call(obj)?返回的正是形如[object Array],所以再結(jié)合上面的class2type變量,正好就可以得到例如。

type([]) => array
type(1) => number

8. 判斷是夠?yàn)榧兇獾膶?duì)象(isPlainObject)

有時(shí)候我們想要符合這樣條件的對(duì)象。但是js中沒(méi)有直接給到能夠判斷是否為純粹的對(duì)象的方法。

// 對(duì)象字面量形式
let obj = {
  name: 'qianlongo'
}
// 通過(guò)Object構(gòu)造函數(shù)創(chuàng)建
let person = new Object({
  name: 'qianlongo',
  sex: 'boy'
})

zepto中是如何判斷的呢?

// 判斷obj是否為純粹的對(duì)象,必須滿(mǎn)足
// 首先必須是對(duì)象  --- isObject(obj)
// 不是window對(duì)象 --- !isWindow(obj)
// 并且原型要和 Object 的原型相等

function isPlainObject(obj) {
  return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
}

Object.getPrototypeOf() 方法返回指定對(duì)象的原型(即, 內(nèi)部[[Prototype]]屬性的值),如果沒(méi)有繼承屬性,則返回 null 。

9. ?判斷是否為空對(duì)象(isEmptyObject)

// 判斷是否為空對(duì)象
// 使用for in遍歷,只要obj有屬性則認(rèn)為不是空對(duì)象

$.isEmptyObject = function (obj) {
  var name
  for (name in obj) return false
  return true
}

主要是通過(guò)走一遍for循環(huán),來(lái)確定,所以會(huì)將以下數(shù)據(jù)也認(rèn)為是空對(duì)象。

  1. null
  2. undefined
  3. []
  4. ''
  5. 1024(數(shù)字)
  6. true or false
  7. {}
  8. new Person() // 自定義的構(gòu)造函數(shù)

所以這里判斷空對(duì)象的初衷到底是不是?只為了判斷形如{},new Object()

結(jié)尾

暫時(shí)就更新這些,后續(xù)在閱讀源碼的過(guò)程中會(huì)陸續(xù)補(bǔ)充

參考資料

讀Zepto源碼之內(nèi)部方法

jQuery.isPlainObject

對(duì)jQuery.isPlainObject()的理解

Object.getPrototypeOf()

文章記錄

  1. 原來(lái)你是這樣的jsonp(原理與具體實(shí)現(xiàn)細(xì)節(jié))

  2. 誰(shuí)說(shuō)你只是"會(huì)用"jQuery?

  3. 向zepto.js學(xué)習(xí)如何手動(dòng)觸發(fā)DOM事件

  4. mouseenter與mouseover為何這般糾纏不清?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 12,448評(píng)論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,745評(píng)論 18 399
  • 第二十四節(jié)關(guān)于補(bǔ)倉(cāng)。 關(guān)于補(bǔ)倉(cāng),對(duì)于我個(gè)人來(lái)講,是不建議的。因在為補(bǔ)倉(cāng)就是你犯下了錯(cuò),導(dǎo)至被套為了降底股票成本,而...
    精彩飛神閱讀 391評(píng)論 0 0
  • 俗話(huà)說(shuō)婚姻是愛(ài)情的墳?zāi)?,多少人結(jié)婚后,愛(ài)情很快便隨之淡去,多了只是柴米油鹽,雖說(shuō)只有兩個(gè)人生活,但是相處的恰到好處...
    逐夢(mèng)扁舟閱讀 490評(píng)論 0 4
  • 其實(shí)昨天上午就把書(shū)看了,晚上一方面是睡得早,另一方面也是因?yàn)楦杏X(jué)如果總是談人格和精神似乎少了點(diǎn)什么,有些空洞。早上...
    萌叔叔666閱讀 1,433評(píng)論 0 0

友情鏈接更多精彩內(nèi)容