• javaScript工具


    随这是来自xe-utils的封装工具

       1 /**
       2  * xe-utils.js v1.8.19
       3  * (c) 2017-2018 Xu Liangzhan
       4  * ISC License.
       5  * @preserve
       6  */
       7 (function (global, factory) {
       8   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory()
       9     : typeof define === 'function' && define.amd ? define(factory)
      10       : (global.XEUtils = factory())
      11 }(this, function () {
      12   'use strict'
      13 
      14   function XEUtils () { }
      15 
      16   var formatString = 'yyyy-MM-dd HH:mm:ss'
      17   var setupDefaults = {
      18     treeOptions: {
      19       parentKey: 'parentId',
      20       key: 'id',
      21       children: 'children'
      22     },
      23     formatDate: formatString + '.SSSZ',
      24     formatString: formatString,
      25     dateDiffRules: [
      26       ['yyyy', 31536000000],
      27       ['MM', 2592000000],
      28       ['dd', 86400000],
      29       ['HH', 3600000],
      30       ['mm', 60000],
      31       ['ss', 1000],
      32       ['S', 0]
      33     ]
      34   }
      35 
      36   /**
      37     * 数组去重
      38     *
      39     * @param {Array} array 数组
      40     * @return {Array}
      41     */
      42   function arrayUniq (array) {
      43     var result = []
      44     baseExports.each(array, function (value) {
      45       if (!result.includes(value)) {
      46         result.push(value)
      47       }
      48     })
      49     return result
      50   }
      51 
      52   /**
      53     * 将多个数的值返回唯一的并集数组
      54     *
      55     * @param {...Array} 数组
      56     * @return {Array}
      57     */
      58   function arrayUnion () {
      59     var args = arguments
      60     var result = []
      61     var index = 0
      62     var len = args.length
      63     for (; index < len; index++) {
      64       result = result.concat(toArray(args[index]))
      65     }
      66     return arrayUniq(result)
      67   }
      68 
      69   function sortByDef (v1, v2) {
      70     return v1 > v2 ? 1 : -1
      71   }
      72 
      73   function sortMultis (name, compares) {
      74     return function (item1, item2) {
      75       var v1 = item1[name]
      76       var v2 = item2[name]
      77       if (v1 === v2) {
      78         return compares ? compares(item1, item2) : 0
      79       }
      80       return sortByDef(v1, v2)
      81     }
      82   }
      83 
      84   function getSortPros (arr, list, iterate, context) {
      85     iterate = baseExports.isArray(iterate) ? iterate : [iterate]
      86     baseExports.arrayEach(iterate, function (item, index) {
      87       baseExports.arrayEach(list, baseExports.isFunction(item) ? function (val, key) {
      88         val[index] = item.call(context, val.data, key, arr)
      89       } : function (val) {
      90         val[index] = val.data[item]
      91       })
      92     })
      93     return iterate
      94   }
      95 
      96   /**
      97     * 数组按属性值升序
      98     *
      99     * @param {Array} arr 数组
     100     * @param {Function/String/Array} iterate 方法或属性
     101     * @param {Object} context 上下文
     102     * @return {Array}
     103     */
     104   function arraySort (arr, iterate, context, STR_UNDEFINED) {
     105     if (arr) {
     106       if (iterate === STR_UNDEFINED) {
     107         return toArray(arr).sort(sortByDef)
     108       }
     109       var compares
     110       var list = arrayMap(arr, function (item) {
     111         return { data: item }
     112       })
     113       var sortPros = getSortPros(arr, list, iterate, context || this)
     114       var len = sortPros.length
     115       if (len) {
     116         while (len >= 0) {
     117           compares = sortMultis(len, compares)
     118           len--
     119         }
     120         list = list.sort(compares)
     121       }
     122       return arrayMap(list, baseExports.property('data'))
     123     }
     124     return []
     125   }
     126 
     127   /**
     128     * 将一个数组随机打乱,返回一个新的数组
     129     *
     130     * @param {Array} array 数组
     131     * @return {Array}
     132     */
     133   function arrayShuffle (array) {
     134     var index
     135     var result = []
     136     var list = baseExports.values(array)
     137     var len = list.length - 1
     138     for (; len >= 0; len--) {
     139       index = len > 0 ? XEUtils.random(0, len) : 0
     140       result.push(list[index])
     141       list.splice(index, 1)
     142     }
     143     return result
     144   }
     145 
     146   /**
     147     * 从一个数组中随机返回几个元素
     148     *
     149     * @param {Array} array 数组
     150     * @param {Number} number 个数
     151     * @return {Array}
     152     */
     153   function arraySample (array, number) {
     154     var result = arrayShuffle(array)
     155     if (arguments.length <= 1) {
     156       return result[0]
     157     }
     158     if (number < result.length) {
     159       result.length = number || 0
     160     }
     161     return result
     162   }
     163 
     164   function createIterateHandle (prop, useArray, restIndex, matchValue, defaultValue) {
     165     return function (obj, iterate, context) {
     166       if (obj && iterate) {
     167         context = context || this
     168         if (prop && obj[prop]) {
     169           return obj[prop](iterate, context)
     170         } else {
     171           if (useArray && baseExports.isArray(obj)) {
     172             for (var index = 0, len = obj.length; index < len; index++) {
     173               if (!!iterate.call(context, obj[index], index, obj) === matchValue) {
     174                 return [true, false, index, obj[index]][restIndex]
     175               }
     176             }
     177           } else {
     178             for (var key in obj) {
     179               if (baseExports._hasOwnProp(obj, key)) {
     180                 if (!!iterate.call(context, obj[key], key, obj) === matchValue) {
     181                   return [true, false, key, obj[key]][restIndex]
     182                 }
     183               }
     184             }
     185           }
     186         }
     187       }
     188       return defaultValue
     189     }
     190   }
     191 
     192   /**
     193     * 对象中的值中的每一项运行给定函数,如果函数对任一项返回true,则返回true,否则返回false
     194     *
     195     * @param {Object} obj 对象/数组
     196     * @param {Function} iterate(item, index, obj) 回调
     197     * @param {Object} context 上下文
     198     * @return {Boolean}
     199     */
     200   var arraySome = createIterateHandle('some', 1, 0, true, false)
     201 
     202   /**
     203     * 对象中的值中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true,否则返回false
     204     *
     205     * @param {Object} obj 对象/数组
     206     * @param {Function} iterate(item, index, obj) 回调
     207     * @param {Object} context 上下文
     208     * @return {Boolean}
     209     */
     210   var arrayEvery = createIterateHandle('every', 1, 1, false, true)
     211 
     212   /**
     213     * 查找匹配第一条数据的键
     214     *
     215     * @param {Object} obj 对象/数组
     216     * @param {Function} iterate(item, index, obj) 回调
     217     * @param {Object} context 上下文
     218     * @return {Object}
     219     */
     220   var findKey = createIterateHandle('', 0, 2, true)
     221 
     222   /**
     223     * 查找匹配第一条数据
     224     *
     225     * @param {Object} obj 对象/数组
     226     * @param {Function} iterate(item, index, obj) 回调
     227     * @param {Object} context 上下文
     228     * @return {Object}
     229     */
     230   var arrayFind = createIterateHandle('find', 1, 3, true)
     231 
     232   /**
     233     * 根据回调过滤数据
     234     *
     235     * @param {Object} obj 对象/数组
     236     * @param {Function} iterate(item, index, obj) 回调
     237     * @param {Object} context 上下文
     238     * @return {Object}
     239     */
     240   function arrayFilter (obj, iterate, context) {
     241     var result = []
     242     if (obj && iterate) {
     243       context = context || this
     244       if (obj.filter) {
     245         return obj.filter(iterate, context)
     246       }
     247       baseExports.each(obj, function (val, key) {
     248         if (iterate.call(context, val, key, obj)) {
     249           result.push(val)
     250         }
     251       })
     252     }
     253     return result
     254   }
     255 
     256   /**
     257     * 指定方法后的返回值组成的新数组
     258     *
     259     * @param {Object} obj 对象/数组
     260     * @param {Function} iterate(item, index, obj) 回调
     261     * @param {Object} context 上下文
     262     * @return {Array}
     263     */
     264   function arrayMap (obj, iterate, context) {
     265     var result = []
     266     if (obj && arguments.length > 1) {
     267       context = context || this
     268       if (!baseExports.isFunction(iterate)) {
     269         iterate = baseExports.property(iterate)
     270       }
     271       if (obj.map) {
     272         return obj.map(iterate, context)
     273       } else {
     274         baseExports.each(obj, function () {
     275           result.push(iterate.apply(context, arguments))
     276         })
     277       }
     278     }
     279     return result
     280   }
     281 
     282   /**
     283     * 求和函数,将数值相加
     284     *
     285     * @param {Array} array 数组
     286     * @param {Function/String} iterate 方法或属性
     287     * @param {Object} context 上下文
     288     * @return {Number}
     289     */
     290   function arraySum (array, iterate, context) {
     291     var result = 0
     292     var toNumber = XEUtils.toNumber
     293     context = context || this
     294     baseExports.each(array, iterate ? baseExports.isFunction(iterate) ? function () {
     295       result += toNumber(iterate.apply(context, arguments))
     296     } : function (val) {
     297       result += toNumber(val[iterate])
     298     } : function (val) {
     299       result += toNumber(val)
     300     })
     301     return result
     302   }
     303 
     304   /**
     305     * 求平均值函数
     306     *
     307     * @param {Array} array 数组
     308     * @param {Function/String} iterate 方法或属性
     309     * @param {Object} context 上下文
     310     * @return {Number}
     311     */
     312   function arrayMean (array, iterate, context) {
     313     return XEUtils.toNumber(arraySum(array, iterate, context || this) / baseExports.getSize(array))
     314   }
     315 
     316   /**
     317     * 接收一个函数作为累加器,数组中的每个值(从左到右)开始合并,最终为一个值。
     318     *
     319     * @param {Array} array 数组
     320     * @param {Function} callback 方法
     321     * @param {Object} initialValue 初始值
     322     * @return {Number}
     323     */
     324   function arrayReduce (array, callback, initialValue) {
     325     if (array) {
     326       var len, reduceMethod
     327       var index = 0
     328       var context = this
     329       var previous = initialValue
     330       var isInitialVal = arguments.length > 2
     331       var keyList = baseExports.keys(array)
     332       if (array.length && array.reduce) {
     333         reduceMethod = function () {
     334           return callback.apply(context, arguments)
     335         }
     336         if (isInitialVal) {
     337           return array.reduce(reduceMethod, previous)
     338         }
     339         return array.reduce(reduceMethod)
     340       }
     341       if (isInitialVal) {
     342         index = 1
     343         previous = array[keyList[0]]
     344       }
     345       for (len = keyList.length; index < len; index++) {
     346         previous = callback.call(context, previous, array[keyList[index]], index, array)
     347       }
     348       return previous
     349     }
     350   }
     351 
     352   /**
     353     * 浅复制数组的一部分到同一数组中的另一个位置,数组大小不变
     354     *
     355     * @param {Array} array 数组
     356     * @param {Number} target 从该位置开始替换数据
     357     * @param {Number} start 从该位置开始读取数据,默认为 0 。如果为负值,表示倒数
     358     * @param {Number} end 到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数
     359     * @return {Array}
     360     */
     361   function arrayCopyWithin (array, target, start, end) {
     362     if (baseExports.isArray(array) && array.copyWithin) {
     363       return array.copyWithin(target, start, end)
     364     }
     365     var replaceIndex, replaceArray
     366     var targetIndex = target >> 0
     367     var startIndex = start >> 0
     368     var len = array.length
     369     var endIndex = arguments.length > 3 ? end >> 0 : len
     370     if (targetIndex < len) {
     371       targetIndex = targetIndex >= 0 ? targetIndex : len + targetIndex
     372       if (targetIndex >= 0) {
     373         startIndex = startIndex >= 0 ? startIndex : len + startIndex
     374         endIndex = endIndex >= 0 ? endIndex : len + endIndex
     375         if (startIndex < endIndex) {
     376           for (replaceIndex = 0, replaceArray = array.slice(startIndex, endIndex); targetIndex < len; targetIndex++) {
     377             if (replaceArray.length <= replaceIndex) {
     378               break
     379             }
     380             array[targetIndex] = replaceArray[replaceIndex++]
     381           }
     382         }
     383       }
     384     }
     385     return array
     386   }
     387 
     388   /**
     389     * 将一个数组分割成大小的组。如果数组不能被平均分配,那么最后一块将是剩下的元素
     390     *
     391     * @param {Array} array 数组
     392     * @param {Number} size 每组大小
     393     * @return {Array}
     394     */
     395   function chunk (array, size) {
     396     var index
     397     var result = []
     398     var arrLen = size >> 0 || 1
     399     if (baseExports.isArray(array)) {
     400       if (arrLen >= 0 && array.length > arrLen) {
     401         index = 0
     402         while (index < array.length) {
     403           result.push(array.slice(index, index + arrLen))
     404           index += arrLen
     405         }
     406       } else {
     407         result = array.length ? [array] : array
     408       }
     409     }
     410     return result
     411   }
     412 
     413   /**
     414    * 根据键数组、值数组对转换为对象
     415    *
     416    * @param {Array} props 键数组
     417    * @param {Number} values 值数组
     418    * @return {Object}
     419    */
     420   function zipObject (props, values) {
     421     var result = {}
     422     values = values || []
     423     baseExports.each(baseExports.values(props), function (val, key) {
     424       result[val] = values[key]
     425     })
     426     return result
     427   }
     428 
     429   /**
     430    * 将每个数组中相应位置的值合并在一起
     431    *
     432    * @param {Array*} array 数组
     433    */
     434   function zip () {
     435     return unzip(arguments)
     436   }
     437 
     438   /**
     439    * 与 zip 相反
     440    *
     441    * @param {Array} arrays 数组集合
     442    */
     443   function unzip (arrays) {
     444     var result = []
     445     var index = 0
     446     var len = XEUtils.max(arrays, function (item) {
     447       return item.length || 0
     448     }).length
     449     for (; index < len; index++) {
     450       result.push(arrayMap(arrays, index))
     451     }
     452     return result
     453   }
     454 
     455   /**
     456    * 将对象或者伪数组转为新数组
     457    *
     458    * @param {Array} obj 数组
     459    * @return {Array}
     460    */
     461   function toArray (array) {
     462     return arrayMap(array, function (item) {
     463       return item
     464     })
     465   }
     466 
     467   /**
     468     * 判断数组是否包含另一数组
     469     *
     470     * @param {Array} array1 数组
     471     * @param {Array} array2 被包含数组
     472     * @return {Boolean}
     473     */
     474   function includeArrays (array1, array2) {
     475     var len
     476     var index = 0
     477     var includes = baseExports.includes
     478     if (baseExports.isArray(array1) && baseExports.isArray(array2)) {
     479       for (len = array2.length; index < len; index++) {
     480         if (!includes(array1, array2[index])) {
     481           return false
     482         }
     483       }
     484       return true
     485     }
     486     return includes(array1, array2)
     487   }
     488 
     489   /**
     490     * 获取数组对象中某属性值,返回一个数组
     491     *
     492     * @param {Array} array 数组
     493     * @param {String} key 属性值
     494     * @return {Array}
     495     */
     496   function pluck (obj, key) {
     497     return arrayMap(obj, key)
     498   }
     499 
     500   function deepGetObj (obj, path) {
     501     var index = 0
     502     var len = path.length
     503     while (obj && index < len) {
     504       obj = obj[path[index++]]
     505     }
     506     return len && obj ? obj : 0
     507   }
     508 
     509   /**
     510    * 在list的每个元素上执行方法,任何传递的额外参数都会在调用方法的时候传递给它
     511    *
     512    * @param {Array} list
     513    * @param {Array/String/Function} path
     514    * @param {...Object} arguments
     515    * @return {Array}
     516    */
     517   function invokeMap (list, path) {
     518     var func
     519     var args = arguments
     520     var params = []
     521     var paths = []
     522     var index = 2
     523     var len = args.length
     524     for (; index < len; index++) {
     525       params.push(args[index])
     526     }
     527     if (baseExports.isArray(path)) {
     528       len = path.length - 1
     529       for (index = 0; index < len; index++) {
     530         paths.push(path[index])
     531       }
     532       path = path[len]
     533     }
     534     return arrayMap(list, function (context) {
     535       if (paths.length) {
     536         context = deepGetObj(context, paths)
     537       }
     538       func = context[path] || path
     539       if (func && func.apply) {
     540         return func.apply(context, params)
     541       }
     542     })
     543   }
     544 
     545   /**
     546     * 将一个带层级的数据列表转成树结构
     547     *
     548     * @param {Array} array 数组
     549     * @param {Object} options {strict: false, parentKey: 'parentId', key: 'id', children: 'children', data: 'data'}
     550     * @return {Array}
     551     */
     552   function toArrayTree (array, options) {
     553     var opts = baseExports.assign({}, setupDefaults.treeOptions, options)
     554     var optStrict = opts.strict
     555     var optKey = opts.key
     556     var optParentKey = opts.parentKey
     557     var optChildren = opts.children
     558     var optSortKey = opts.sortKey
     559     var optReverse = opts.reverse
     560     var optData = opts.data
     561     var result = []
     562     var treeMap = {}
     563     var idList, id, treeData, parentId
     564 
     565     if (optSortKey) {
     566       array = arraySort(baseExports.clone(array), optSortKey)
     567       if (optReverse) {
     568         array = array.reverse()
     569       }
     570     }
     571 
     572     idList = arrayMap(array, function (item) {
     573       return item[optKey]
     574     })
     575 
     576     baseExports.each(array, function (item) {
     577       id = item[optKey]
     578 
     579       if (optData) {
     580         treeData = {}
     581         treeData[optData] = item
     582       } else {
     583         treeData = item
     584       }
     585 
     586       parentId = item[optParentKey]
     587       treeMap[id] = treeMap[id] || []
     588       treeMap[parentId] = treeMap[parentId] || []
     589       treeMap[parentId].push(treeData)
     590       treeData[optKey] = id
     591       treeData[optParentKey] = parentId
     592       treeData[optChildren] = treeMap[id]
     593 
     594       if (!optStrict || (optStrict && !parentId)) {
     595         if (!baseExports.includes(idList, parentId)) {
     596           result.push(treeData)
     597         }
     598       }
     599     })
     600 
     601     if (optStrict) {
     602       strictTree(array, optChildren)
     603     }
     604 
     605     return result
     606   }
     607 
     608   function strictTree (array, optChildren) {
     609     baseExports.each(array, function (item) {
     610       if (item.children && !item.children.length) {
     611         baseExports.remove(item, optChildren)
     612       }
     613     })
     614   }
     615 
     616   function unTreeList (result, array, opts) {
     617     var children
     618     var optChildren = opts.children
     619     var optData = opts.data
     620     baseExports.each(array, function (item) {
     621       children = item[optChildren]
     622       if (optData) {
     623         item = item[optData]
     624       }
     625       result.push(item)
     626       if (children) {
     627         unTreeList(result, children, opts)
     628       }
     629     })
     630     return result
     631   }
     632 
     633   /**
     634     * 将一个树结构转成数组列表
     635     *
     636     * @param {Array} array 数组
     637     * @param {Object} options {children: 'children', data: 'data'}
     638     * @return {Array}
     639     */
     640   function toTreeArray (array, options) {
     641     return unTreeList([], array, baseExports.assign({}, setupDefaults.treeOptions, options))
     642   }
     643 
     644   function createTreeFunc (handle) {
     645     return function (obj, iterate, options, context) {
     646       var opts = options || {}
     647       var optChildren = opts.children || 'children'
     648       return handle(null, obj, iterate, context || this, [], optChildren, opts.mapChildren || optChildren)
     649     }
     650   }
     651 
     652   function findTreeItem (parent, obj, iterate, context, path, parseChildren, mapChildren) {
     653     var item, key, index, len, paths, match
     654     if (baseExports.isArray(obj)) {
     655       for (index = 0, len = obj.length; index < len; index++) {
     656         item = obj[index]
     657         paths = path.concat(['' + index])
     658         if (iterate.call(context, item, index, obj, paths, parent)) {
     659           return { index: index, item: item, path: paths, items: obj, parent: parent }
     660         }
     661         if (parseChildren && item) {
     662           match = findTreeItem(item, item[parseChildren], iterate, context, paths.concat([parseChildren]), parseChildren, mapChildren)
     663           if (match) {
     664             return match
     665           }
     666         }
     667       }
     668     } else {
     669       for (key in obj) {
     670         if (baseExports._hasOwnProp(obj, key)) {
     671           item = obj[key]
     672           paths = path.concat([key])
     673           if (iterate.call(context, item, index, obj, paths, parent)) {
     674             return { index: key, item: item, path: paths, items: obj }
     675           }
     676           if (parseChildren && item) {
     677             match = findTreeItem(item, item[parseChildren], iterate, context, paths.concat([parseChildren]), parseChildren, mapChildren)
     678             if (match) {
     679               return match
     680             }
     681           }
     682         }
     683       }
     684     }
     685   }
     686 
     687   /**
     688     * 从树结构中查找匹配第一条数据的键、值、路径
     689     *
     690     * @param {Object} obj 对象/数组
     691     * @param {Function} iterate(item, index, items, path, parent) 回调
     692     * @param {Object} options {children: 'children'}
     693     * @param {Object} context 上下文
     694     * @return {Object} { item, index, items, path }
     695     */
     696   var findTree = createTreeFunc(findTreeItem)
     697 
     698   function eachTreeItem (parent, obj, iterate, context, path, parseChildren, mapChildren) {
     699     var paths
     700     baseExports.each(obj, function (item, index) {
     701       paths = path.concat(['' + index])
     702       iterate.call(context, item, index, obj, paths, parent)
     703       if (item && parseChildren) {
     704         eachTreeItem(item, item[parseChildren], iterate, context, paths, parseChildren, mapChildren)
     705       }
     706     })
     707   }
     708 
     709   /**
     710     * 从树结构中遍历数据的键、值、路径
     711     *
     712     * @param {Object} obj 对象/数组
     713     * @param {Function} iterate(item, index, items, path, parent) 回调
     714     * @param {Object} options {children: 'children', mapChildren: 'children}
     715     * @param {Object} context 上下文
     716     */
     717   var eachTree = createTreeFunc(eachTreeItem)
     718 
     719   function mapTreeItem (parent, obj, iterate, context, path, parseChildren, mapChildren) {
     720     var paths, rest
     721     return arrayMap(obj, function (item, index) {
     722       paths = path.concat(['' + index])
     723       rest = iterate.call(context, item, index, obj, paths, parent)
     724       if (rest && item && parseChildren && item[parseChildren]) {
     725         rest[mapChildren] = mapTreeItem(item, item[parseChildren], iterate, context, paths, parseChildren, mapChildren)
     726       }
     727       return rest
     728     })
     729   }
     730 
     731   /**
     732     * 从树结构中指定方法后的返回值组成的新数组
     733     *
     734     * @param {Object} obj 对象/数组
     735     * @param {Function} iterate(item, index, items, path, parent) 回调
     736     * @param {Object} options {children: 'children'}
     737     * @param {Object} context 上下文
     738     * @return {Object/Array}
     739     */
     740   var mapTree = createTreeFunc(mapTreeItem)
     741 
     742   /**
     743     * 从树结构中根据回调过滤数据
     744     *
     745     * @param {Object} obj 对象/数组
     746     * @param {Function} iterate(item, index, items, path, parent) 回调
     747     * @param {Object} options {children: 'children'}
     748     * @param {Object} context 上下文
     749     * @return {Array}
     750     */
     751   function filterTree (obj, iterate, options, context) {
     752     var result = []
     753     if (obj && iterate) {
     754       context = context || this
     755       eachTree(obj, function (item, index, items, path, parent) {
     756         if (iterate.call(context, item, index, items, path, parent)) {
     757           result.push(item)
     758         }
     759       }, options)
     760     }
     761     return result
     762   }
     763 
     764   var arrayExports = {
     765     uniq: arrayUniq,
     766     union: arrayUnion,
     767     sortBy: arraySort,
     768     shuffle: arrayShuffle,
     769     sample: arraySample,
     770     some: arraySome,
     771     every: arrayEvery,
     772     filter: arrayFilter,
     773     find: arrayFind,
     774     findKey: findKey,
     775     map: arrayMap,
     776     sum: arraySum,
     777     mean: arrayMean,
     778     reduce: arrayReduce,
     779     copyWithin: arrayCopyWithin,
     780     chunk: chunk,
     781     zip: zip,
     782     unzip: unzip,
     783     zipObject: zipObject,
     784     toArray: toArray,
     785     includeArrays: includeArrays,
     786     pluck: pluck,
     787     invoke: invokeMap,
     788     invokeMap: invokeMap,
     789     toArrayTree: toArrayTree,
     790     toTreeArray: toTreeArray,
     791     findTree: findTree,
     792     eachTree: eachTree,
     793     mapTree: mapTree,
     794     filterTree: filterTree
     795   }
     796 
     797   var STRING_UNDEFINED = 'undefined'
     798   var objectToString = Object.prototype.toString
     799   var objectAssignFns = Object.assign
     800 
     801   function hasOwnProp (obj, key) {
     802     return obj.hasOwnProperty(key)
     803   }
     804 
     805   /* eslint-disable valid-typeof */
     806   function createInTypeof (type) {
     807     return function (obj) {
     808       return typeof obj === type
     809     }
     810   }
     811 
     812   function createInInObjectString (type) {
     813     return function (obj) {
     814       return '[object ' + type + ']' === objectToString.call(obj)
     815     }
     816   }
     817 
     818   /**
     819     * 指定方法后的返回值组成的新对象
     820     *
     821     * @param {Object} obj 对象/数组
     822     * @param {Function} iterate(item, index, obj) 回调
     823     * @param {Object} context 上下文
     824     * @return {Object}
     825     */
     826   function objectMap (obj, iterate, context) {
     827     var result = {}
     828     if (obj) {
     829       if (iterate) {
     830         context = context || this
     831         if (!isFunction(iterate)) {
     832           iterate = property(iterate)
     833         }
     834         each(obj, function (val, index) {
     835           result[index] = iterate.call(context, val, index, obj)
     836         })
     837       } else {
     838         return obj
     839       }
     840     }
     841     return result
     842   }
     843 
     844   function cloneObj (obj) {
     845     var result = {}
     846     each(obj, function (val, key) {
     847       result[key] = deepClone(val)
     848     })
     849     return result
     850   }
     851 
     852   function cloneArr (arr) {
     853     return XEUtils.map(arr, deepClone)
     854   }
     855 
     856   function deepClone (obj) {
     857     return isPlainObject(obj) ? cloneObj(obj) : isArray(obj) ? cloneArr(obj) : obj
     858   }
     859 
     860   /**
     861     * 浅拷贝/深拷贝
     862     *
     863     * @param {Object} obj 对象/数组
     864     * @param {Boolean} deep 是否深拷贝
     865     * @return {Object}
     866     */
     867   function clone (obj, deep) {
     868     if (obj) {
     869       return deep ? deepClone(obj) : objectAssign(isPlainObject(obj) ? {} : [], obj)
     870     }
     871     return obj
     872   }
     873 
     874   /**
     875     * 该方法和 setTimeout 一样的效果,区别就是支持上下文和额外参数
     876     *
     877     * @param {Function} callback 函数
     878     * @param {Number} wait 延迟毫秒
     879     * @param {*} args 额外的参数
     880     * @return {Number}
     881    */
     882   function delay (callback, wait) {
     883     var args = arraySlice(arguments, 2)
     884     var context = this
     885     return setTimeout(function () {
     886       callback.apply(context, args)
     887     }, wait)
     888   }
     889 
     890   /**
     891     * 创建一个绑定上下文的函数
     892     *
     893     * @param {Function} callback 函数
     894     * @param {Object} context 上下文
     895     * @param {*} args 额外的参数
     896     * @return {Object}
     897     */
     898   function bind (callback, context) {
     899     var args = arraySlice(arguments, 2)
     900     context = context || this
     901     return function () {
     902       return callback.apply(context, arraySlice(arguments).concat(args))
     903     }
     904   }
     905 
     906   /**
     907     * 创建一个只能调用一次的函数,只会返回第一次执行后的结果
     908     *
     909     * @param {Function} callback 函数
     910     * @param {Object} context 上下文
     911     * @param {*} args 额外的参数
     912     * @return {Object}
     913     */
     914   function once (callback, context) {
     915     var done = false
     916     var rest = null
     917     var args = arraySlice(arguments, 2)
     918     context = context || this
     919     return function () {
     920       if (done) {
     921         return rest
     922       }
     923       rest = callback.apply(context, arraySlice(arguments).concat(args))
     924       done = true
     925       return rest
     926     }
     927   }
     928 
     929   /**
     930     * 创建一个函数, 调用次数超过 count 次之后执行回调并将所有结果记住后返回
     931     *
     932     * @param {Number} count 调用次数
     933     * @param {Function} callback 完成回调
     934     * @return {Object}
     935     */
     936   function after (count, callback, context) {
     937     var runCount = 0
     938     var rests = []
     939     context = context || this
     940     return function () {
     941       runCount++
     942       if (runCount <= count) {
     943         rests.push(arguments[0])
     944       }
     945       if (runCount >= count) {
     946         callback.apply(context, [rests].concat(arraySlice(arguments)))
     947       }
     948     }
     949   }
     950 
     951   /**
     952     * 创建一个函数, 调用次数不超过 count 次之前执行回调并将所有结果记住后返回
     953     *
     954     * @param {Number} count 调用次数
     955     * @param {Function} callback 完成回调
     956     * @return {Object}
     957     */
     958   function before (count, callback, context) {
     959     var runCount = 0
     960     var rests = []
     961     context = context || this
     962     return function () {
     963       runCount++
     964       if (runCount < count) {
     965         rests.push(arguments[0])
     966         callback.apply(context, [rests].concat(arraySlice(arguments)))
     967       }
     968     }
     969   }
     970 
     971   function isNumberFinite (obj) {
     972     return isNumber(obj) && isFinite(obj)
     973   }
     974 
     975   /**
     976     * 判断是否Undefined
     977     *
     978     * @param {Object} obj 对象
     979     * @return {Boolean}
     980     */
     981   var isUndefined = createInTypeof(STRING_UNDEFINED)
     982 
     983   /**
     984     * 判断是否数组
     985     *
     986     * @param {Object} obj 对象
     987     * @return {Boolean}
     988     */
     989   var isArray = Array.isArray || createInInObjectString('Array')
     990 
     991   /**
     992     * 判断是否小数
     993     *
     994     * @param {Number} obj 数值
     995     * @return {Boolean}
     996     */
     997   function isFloat (obj) {
     998     return obj !== null && !isNaN(obj) && !isArray(obj) && !isInteger(obj)
     999   }
    1000 
    1001   /**
    1002     * 判断是否整数
    1003     *
    1004     * @param {Number, String} number 数值
    1005     * @return {Boolean}
    1006     */
    1007   var isInteger = function (obj) {
    1008     return obj !== null && !isNaN(obj) && !isArray(obj) && obj % 1 === 0
    1009   }
    1010 
    1011   /**
    1012     * 判断是否方法
    1013     *
    1014     * @param {Object} obj 对象
    1015     * @return {Boolean}
    1016     */
    1017   var isFunction = createInTypeof('function')
    1018 
    1019   /**
    1020     * 判断是否Boolean对象
    1021     *
    1022     * @param {Object} obj 对象
    1023     * @return {Boolean}
    1024     */
    1025   var isBoolean = createInTypeof('boolean')
    1026 
    1027   /**
    1028     * 判断是否String对象
    1029     *
    1030     * @param {Object} obj 对象
    1031     * @return {Boolean}
    1032     */
    1033   var isString = createInTypeof('string')
    1034 
    1035   /**
    1036     * 判断是否Number对象
    1037     *
    1038     * @param {Object} obj 对象
    1039     * @return {Boolean}
    1040     */
    1041   var isNumber = createInTypeof('number')
    1042 
    1043   /**
    1044     * 判断是否RegExp对象
    1045     *
    1046     * @param {Object} obj 对象
    1047     * @return {Boolean}
    1048     */
    1049   var isRegExp = createInInObjectString('RegExp')
    1050 
    1051   /**
    1052     * 判断是否Object对象
    1053     *
    1054     * @param {Object} obj 对象
    1055     * @return {Boolean}
    1056     */
    1057   var isObject = createInTypeof('object')
    1058 
    1059   /**
    1060     * 判断是否对象
    1061     *
    1062     * @param {Object} obj 对象
    1063     * @return {Boolean}
    1064     */
    1065   function isPlainObject (obj) {
    1066     return obj ? obj.constructor === Object : false
    1067   }
    1068 
    1069   /**
    1070     * 判断是否Date对象
    1071     *
    1072     * @param {Object} obj 对象
    1073     * @return {Boolean}
    1074     */
    1075   var isDate = createInInObjectString('Date')
    1076 
    1077   /**
    1078     * 判断是否Error对象
    1079     *
    1080     * @param {Object} obj 对象
    1081     * @return {Boolean}
    1082     */
    1083   var isError = createInInObjectString('Error')
    1084 
    1085   /**
    1086     * 判断是否TypeError对象
    1087     *
    1088     * @param {Object} obj 对象
    1089     * @return {Boolean}
    1090     */
    1091   function isTypeError (obj) {
    1092     return obj ? obj.constructor === TypeError : false
    1093   }
    1094 
    1095   /**
    1096     * 判断是否为空,包括空对象、空数值、空字符串
    1097     *
    1098     * @param {Object} obj 对象
    1099     * @return {Boolean}
    1100     */
    1101   function isEmpty (obj) {
    1102     for (var key in obj) {
    1103       return false
    1104     }
    1105     return true
    1106   }
    1107 
    1108   /**
    1109     * 判断是否为Null
    1110     *
    1111     * @param {Object} obj 对象
    1112     * @return {Boolean}
    1113     */
    1114   function isNull (obj) {
    1115     return obj === null
    1116   }
    1117 
    1118   /**
    1119     * 判断是否Symbol对象
    1120     *
    1121     * @param {Object} obj 对象
    1122     * @return {Boolean}
    1123     */
    1124   var supportSymbol = typeof Symbol !== STRING_UNDEFINED
    1125   function isSymbol (obj) {
    1126     return supportSymbol && Symbol.isSymbol ? Symbol.isSymbol(obj) : (typeof obj === 'symbol')
    1127   }
    1128 
    1129   /**
    1130     * 判断是否Arguments对象
    1131     *
    1132     * @param {Object} obj 对象
    1133     * @return {Boolean}
    1134     */
    1135   var isArguments = createInInObjectString('Arguments')
    1136 
    1137   /**
    1138     * 判断是否Element对象
    1139     *
    1140     * @param {Object} obj 对象
    1141     * @return {Boolean}
    1142     */
    1143   function isElement (obj) {
    1144     return !!(obj && isString(obj.nodeName) && isNumber(obj.nodeType))
    1145   }
    1146 
    1147   /**
    1148     * 判断是否Document对象
    1149     *
    1150     * @param {Object} obj 对象
    1151     * @return {Boolean}
    1152     */
    1153   var supportDocument = typeof document !== STRING_UNDEFINED
    1154   function isDocument (obj) {
    1155     return !!(obj && obj.nodeType === 9 && supportDocument)
    1156   }
    1157 
    1158   /**
    1159     * 判断是否Window对象
    1160     *
    1161     * @param {Object} obj 对象
    1162     * @return {Boolean}
    1163     */
    1164   var supportWindow = typeof window !== STRING_UNDEFINED
    1165   function isWindow (obj) {
    1166     return !!(obj && obj === obj.window && supportWindow)
    1167   }
    1168 
    1169   /**
    1170     * 判断是否FormData对象
    1171     *
    1172     * @param {Object} obj 对象
    1173     * @return {Boolean}
    1174     */
    1175   var supportFormData = typeof FormData !== STRING_UNDEFINED
    1176   function isFormData (obj) {
    1177     return supportFormData && obj instanceof FormData
    1178   }
    1179 
    1180   /**
    1181     * 判断是否Map对象
    1182     *
    1183     * @param {Object} obj 对象
    1184     * @return {Boolean}
    1185    */
    1186   var supportMap = typeof Map !== STRING_UNDEFINED
    1187   function isMap (obj) {
    1188     return supportMap && obj instanceof Map
    1189   }
    1190 
    1191   /**
    1192     * 判断是否WeakMap对象
    1193     *
    1194     * @param {Object} obj 对象
    1195     * @return {Boolean}
    1196    */
    1197   var supportWeakMap = typeof WeakMap !== STRING_UNDEFINED
    1198   function isWeakMap (obj) {
    1199     return supportWeakMap && obj instanceof WeakMap
    1200   }
    1201 
    1202   /**
    1203     * 判断是否Set对象
    1204     *
    1205     * @param {Object} obj 对象
    1206     * @return {Boolean}
    1207    */
    1208   var supportSet = typeof Set !== STRING_UNDEFINED
    1209   function isSet (obj) {
    1210     return supportSet && obj instanceof Set
    1211   }
    1212 
    1213   /**
    1214     * 判断是否WeakSet对象
    1215     *
    1216     * @param {Object} obj 对象
    1217     * @return {Boolean}
    1218    */
    1219   var supportWeakSet = typeof WeakSet !== STRING_UNDEFINED
    1220   function isWeakSet (obj) {
    1221     return supportWeakSet && obj instanceof WeakSet
    1222   }
    1223 
    1224   /**
    1225     * 判断是否闰年
    1226     *
    1227     * @param {Date} date 日期或数字
    1228     * @return {Boolean}
    1229     */
    1230   function isLeapYear (date) {
    1231     var year
    1232     var currentDate = date ? XEUtils.toStringDate(date) : new Date()
    1233     if (isDate(currentDate)) {
    1234       year = currentDate.getFullYear()
    1235       return (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0)
    1236     }
    1237     return false
    1238   }
    1239 
    1240   /**
    1241    * 判断属性中的键和值是否包含在对象中
    1242    *
    1243    * @param {Object/Array} obj 对象
    1244    * @param {Object} source 值
    1245    * @return {Boolean}
    1246    */
    1247   function isMatch (obj, source) {
    1248     var objKeys = objectKeys(obj)
    1249     var sourceKeys = objectKeys(source)
    1250     if (sourceKeys.length) {
    1251       if (XEUtils.includeArrays(objKeys, sourceKeys)) {
    1252         return XEUtils.some(sourceKeys, function (key2) {
    1253           return findIndexOf(objKeys, function (key1) {
    1254             return key1 === key2 && isEqual(obj[key1], source[key2])
    1255           }) > -1
    1256         })
    1257       }
    1258     } else {
    1259       return true
    1260     }
    1261     return isEqual(obj, source)
    1262   }
    1263 
    1264   /**
    1265    * 深度比较两个对象之间的值是否相等
    1266    *
    1267    * @param {Object} obj1 值1
    1268    * @param {Object} obj2 值2
    1269    * @return {Boolean}
    1270    */
    1271   function isEqual (obj1, obj2) {
    1272     return equalCompare(obj1, obj2, defaultCompare)
    1273   }
    1274 
    1275   function defaultCompare (v1, v2) {
    1276     return v1 === v2
    1277   }
    1278 
    1279   function equalCompare (val1, val2, compare, func, key, obj1, obj2) {
    1280     if (val1 && val2 && !isNumber(val1) && !isNumber(val2) && !isString(val1) && !isString(val2)) {
    1281       if (isRegExp(val1)) {
    1282         return compare('' + val1, '' + val2, key, obj1, obj2)
    1283       } if (isDate(val1) || isBoolean(val1)) {
    1284         return compare(+val1, +val2, key, obj1, obj2)
    1285       } else {
    1286         var result, val1Keys, val2Keys
    1287         var isObj1Arr = isArray(val1)
    1288         var isObj2Arr = isArray(val2)
    1289         if (isObj1Arr || isObj2Arr ? isObj1Arr && isObj2Arr : val1.constructor === val2.constructor) {
    1290           val1Keys = objectKeys(val1)
    1291           val2Keys = objectKeys(val2)
    1292           if (func) {
    1293             result = func(val1, val2, key)
    1294           }
    1295           if (val1Keys.length === val2Keys.length) {
    1296             return isUndefined(result) ? XEUtils.every(val1Keys, function (key, index) {
    1297               return key === val2Keys[index] && equalCompare(val1[key], val2[val2Keys[index]], compare, func, isObj1Arr || isObj2Arr ? index : key, val1, val2)
    1298             }) : !!result
    1299           }
    1300           return false
    1301         }
    1302       }
    1303     }
    1304     return compare(val1, val2, key, obj1, obj2)
    1305   }
    1306 
    1307   /**
    1308    * 深度比较两个对象之间的值是否相等,使用自定义比较函数
    1309    *
    1310    * @param {Object} obj1 值1
    1311    * @param {Object} obj2 值2
    1312    * @param {Function} func 自定义函数
    1313    * @return {Boolean}
    1314    */
    1315   function isEqualWith (obj1, obj2, func) {
    1316     if (isFunction(func)) {
    1317       return equalCompare(obj1, obj2, function (v1, v2, key, obj1, obj2) {
    1318         var result = func(v1, v2, key, obj1, obj2)
    1319         return isUndefined(result) ? defaultCompare(v1, v2) : !!result
    1320       }, func)
    1321     }
    1322     return equalCompare(obj1, obj2, defaultCompare)
    1323   }
    1324 
    1325   /**
    1326    * 返回一个获取对象属性的函数
    1327    *
    1328    * @param {String} name 属性名
    1329    * @param {Object} defs 空值
    1330    */
    1331   function property (name, defs) {
    1332     return function (obj) {
    1333       return obj === null ? defs : obj[name]
    1334     }
    1335   }
    1336 
    1337   /**
    1338     * 获取对象类型
    1339     *
    1340     * @param {Object} obj 对象
    1341     * @return {String}
    1342     */
    1343   function getType (obj) {
    1344     if (obj === null) {
    1345       return '' + obj
    1346     }
    1347     if (isSymbol(obj)) {
    1348       return 'symbol'
    1349     }
    1350     if (isDate(obj)) {
    1351       return 'date'
    1352     }
    1353     if (isArray(obj)) {
    1354       return 'array'
    1355     }
    1356     if (isRegExp(obj)) {
    1357       return 'regexp'
    1358     }
    1359     if (isError(obj)) {
    1360       return 'error'
    1361     }
    1362     return typeof obj
    1363   }
    1364 
    1365   /**
    1366     * 获取一个全局唯一标识
    1367     *
    1368     * @param {String} prefix 前缀
    1369     * @return {Number}
    1370     */
    1371   var __uniqueId = 0
    1372   function uniqueId (prefix) {
    1373     return (prefix ? '' + prefix : 0) + ++__uniqueId
    1374   }
    1375 
    1376   /**
    1377     * 返回对象的长度
    1378     *
    1379     * @param {Object} obj 对象
    1380     * @return {Number}
    1381     */
    1382   function getSize (obj) {
    1383     var len = 0
    1384     if (isString(obj) || isArray(obj)) {
    1385       return obj.length
    1386     }
    1387     each(obj, function () {
    1388       len++
    1389     })
    1390     return len
    1391   }
    1392 
    1393   /**
    1394    * 裁剪 Arguments 或数组 array,从 start 位置开始到 end 结束,但不包括 end 本身的位置
    1395    * @param {Array/Arguments} array 数组或Arguments
    1396    * @param {Number} startIndex 开始索引
    1397    * @param {Number} endIndex 结束索引
    1398    */
    1399   function arraySlice (array, startIndex, endIndex) {
    1400     var result = []
    1401     if (array) {
    1402       for (startIndex = startIndex || 0, endIndex = endIndex || array.length; startIndex < endIndex; startIndex++) {
    1403         result.push(array[startIndex])
    1404       }
    1405     }
    1406     return result
    1407   }
    1408 
    1409   function createIndexOf (name, callback) {
    1410     return function (obj, val) {
    1411       if (obj) {
    1412         if (isString(obj) || isArray(obj)) {
    1413           if (obj[name]) {
    1414             return obj[name](val)
    1415           }
    1416           return callback(obj, val)
    1417         }
    1418         for (var key in obj) {
    1419           if (hasOwnProp(obj, key)) {
    1420             if (val === obj[key]) {
    1421               return key
    1422             }
    1423           }
    1424         }
    1425       }
    1426       return -1
    1427     }
    1428   }
    1429 
    1430   /**
    1431     * 返回对象第一个索引值
    1432     *
    1433     * @param {Object} obj 对象
    1434     * @param {Object} val 值
    1435     * @return {Number}
    1436     */
    1437   var indexOf = createIndexOf('indexOf', function (obj, val) {
    1438     for (var index = 0, len = obj.length; index < len; index++) {
    1439       if (val === obj[index]) {
    1440         return index
    1441       }
    1442     }
    1443   })
    1444 
    1445   /**
    1446     * 从最后开始的索引值,返回对象第一个索引值
    1447     *
    1448     * @param {Object} array 对象
    1449     * @param {Object} val 值
    1450     * @return {Number}
    1451     */
    1452   var lastIndexOf = createIndexOf('lastIndexOf', function (obj, val) {
    1453     for (var len = obj.length - 1; len >= 0; len--) {
    1454       if (val === obj[len]) {
    1455         return len
    1456       }
    1457     }
    1458     return -1
    1459   })
    1460 
    1461   function createiterateIndexOf (callback) {
    1462     return function (obj, iterate, context) {
    1463       if (obj && isFunction(iterate)) {
    1464         context = this || context
    1465         if (isArray(obj) || isString(obj)) {
    1466           return callback(obj, iterate, context)
    1467         }
    1468         for (var key in obj) {
    1469           if (hasOwnProp(obj, key)) {
    1470             if (iterate.call(context, obj[key], key, obj)) {
    1471               return key
    1472             }
    1473           }
    1474         }
    1475       }
    1476       return -1
    1477     }
    1478   }
    1479 
    1480   /**
    1481     * 返回对象第一个索引值
    1482     *
    1483     * @param {Object} obj 对象/数组
    1484     * @param {Function} iterate(item, index, obj) 回调
    1485     * @param {Object} context 上下文
    1486     * @return {Object}
    1487     */
    1488   var findIndexOf = createiterateIndexOf(function (obj, iterate, context) {
    1489     for (var index = 0, len = obj.length; index < len; index++) {
    1490       if (iterate.call(context, obj[index], index, obj)) {
    1491         return index
    1492       }
    1493     }
    1494     return -1
    1495   })
    1496 
    1497   /**
    1498     * 从最后开始的索引值,返回对象第一个索引值
    1499     *
    1500     * @param {Object} obj 对象/数组
    1501     * @param {Function} iterate(item, index, obj) 回调
    1502     * @param {Object} context 上下文
    1503     * @return {Object}
    1504     */
    1505   var findLastIndexOf = createiterateIndexOf(function (obj, iterate, context) {
    1506     for (var len = obj.length - 1; len >= 0; len--) {
    1507       if (iterate.call(context, obj[len], len, obj)) {
    1508         return len
    1509       }
    1510     }
    1511     return -1
    1512   })
    1513 
    1514   /**
    1515     * 判断对象是否包含该值,成功返回true否则false
    1516     *
    1517     * @param {Object} obj 对象
    1518     * @param {Object} val 值
    1519     * @return {Boolean}
    1520     */
    1521   function includes (obj, val) {
    1522     return indexOf(obj, val) !== -1
    1523   }
    1524 
    1525   function extend (destination, args, isClone) {
    1526     var len = args.length
    1527     for (var source, index = 1; index < len; index++) {
    1528       source = args[index]
    1529       arrayEach(objectKeys(args[index]), isClone ? function (key) {
    1530         destination[key] = clone(source[key], isClone)
    1531       } : function (key) {
    1532         destination[key] = source[key]
    1533       })
    1534     }
    1535     return destination
    1536   }
    1537 
    1538   /**
    1539     * 将一个或者多个对象值解构到目标对象
    1540     *
    1541     * @param {Object} destination 目标对象
    1542     * @param {...Object}
    1543     * @return {Boolean}
    1544     */
    1545   function destructuring (destination, sources) {
    1546     if (destination && sources) {
    1547       var rest = objectAssign.apply(this, [{}].concat(arraySlice(arguments, 1)))
    1548       var restKeys = objectKeys(rest)
    1549       arrayEach(objectKeys(destination), function (key) {
    1550         if (includes(restKeys, key)) {
    1551           destination[key] = rest[key]
    1552         }
    1553       })
    1554     }
    1555     return destination
    1556   }
    1557 
    1558   /**
    1559     * 浅拷贝一个或者多个对象到目标对象中
    1560     *
    1561     * @param {Object} obj 目标对象
    1562     * @param {...Object}
    1563     * @return {Boolean}
    1564     */
    1565   var objectAssign = function (target) {
    1566     if (target) {
    1567       var args = arguments
    1568       if (target === true) {
    1569         if (args.length > 1) {
    1570           target = isArray(target[1]) ? [] : {}
    1571           return extend(target, args, true)
    1572         }
    1573       } else {
    1574         return objectAssignFns ? objectAssignFns.apply(Object, args) : extend(target, args)
    1575       }
    1576     }
    1577     return target
    1578   }
    1579 
    1580   /**
    1581     * 字符串转JSON
    1582     *
    1583     * @param {String} str 字符串
    1584     * @return {Object} 返回转换后对象
    1585     */
    1586   function toStringJSON (str) {
    1587     if (isObject(str)) {
    1588       return str
    1589     } else if (isString(str)) {
    1590       try {
    1591         return JSON.parse(str)
    1592       } catch (e) { }
    1593     }
    1594     return {}
    1595   }
    1596 
    1597   /**
    1598     * JSON转字符串
    1599     *
    1600     * @param {Object} obj 对象
    1601     * @return {String} 返回字符串
    1602     */
    1603   function toJSONString (obj) {
    1604     return JSON.stringify(obj) || ''
    1605   }
    1606 
    1607   function deleteProperty (obj, property) {
    1608     try {
    1609       delete obj[property]
    1610     } catch (e) {
    1611       obj[property] = undefined
    1612     }
    1613   }
    1614 
    1615   /**
    1616     * 清空对象
    1617     *
    1618     * @param {Object} obj 对象
    1619     * @param {*} defs 默认值,如果不传(清空所有属性)、如果传对象(清空并继承)、如果传值(给所有赋值)
    1620     * @param {Object/Array} assigns 默认值
    1621     * @return {Object}
    1622     */
    1623   function clearObject (obj, defs, assigns) {
    1624     if (obj) {
    1625       var len
    1626       var isDefs = arguments.length > 1 && (defs === null || !isObject(defs))
    1627       var extds = isDefs ? assigns : defs
    1628       if (isPlainObject(obj)) {
    1629         objectEach(obj, isDefs ? function (val, key) {
    1630           obj[key] = defs
    1631         } : function (val, key) {
    1632           deleteProperty(obj, key)
    1633         })
    1634         if (extds) {
    1635           objectAssign(obj, extds)
    1636         }
    1637       } else if (isArray(obj)) {
    1638         if (isDefs) {
    1639           len = obj.length
    1640           while (len > 0) {
    1641             len--
    1642             obj[len] = defs
    1643           }
    1644         } else {
    1645           obj.length = 0
    1646         }
    1647         if (extds) {
    1648           obj.push.apply(obj, extds)
    1649         }
    1650       }
    1651     }
    1652     return obj
    1653   }
    1654 
    1655   function pluckProperty (name) {
    1656     return function (obj, key) {
    1657       return key === name
    1658     }
    1659   }
    1660 
    1661   /**
    1662     * 移除对象属性
    1663     *
    1664     * @param {Object/Array} obj 对象/数组
    1665     * @param {Function/String} iterate 方法或属性
    1666     * @param {Object} context 上下文
    1667     * @return {Object/Array}
    1668     */
    1669   function removeObject (obj, iterate, context) {
    1670     if (obj) {
    1671       if (arguments.length > 1) {
    1672         var removeKeys = []
    1673         var rest = []
    1674         context = context || this
    1675         if (!isFunction(iterate)) {
    1676           iterate = pluckProperty(iterate)
    1677         }
    1678         each(obj, function (item, index, rest) {
    1679           if (iterate.call(context, item, index, rest)) {
    1680             removeKeys.push(index)
    1681           }
    1682         })
    1683         if (isArray(obj)) {
    1684           lastEach(removeKeys, function (item, key) {
    1685             rest.push(obj[item])
    1686             obj.splice(item, 1)
    1687           })
    1688         } else {
    1689           rest = {}
    1690           arrayEach(removeKeys, function (key) {
    1691             rest[key] = obj[key]
    1692             deleteProperty(obj, key)
    1693           })
    1694         }
    1695         return rest
    1696       }
    1697       return clearObject(obj)
    1698     }
    1699     return obj
    1700   }
    1701 
    1702   function createGetObjects (name, getIndex) {
    1703     var proMethod = Object[name]
    1704     return function (obj) {
    1705       var result = []
    1706       if (obj) {
    1707         if (proMethod) {
    1708           return proMethod(obj)
    1709         }
    1710         each(obj, getIndex > 1 ? function (key) {
    1711           result.push(['' + key, obj[key]])
    1712         } : function () {
    1713           result.push(arguments[getIndex])
    1714         })
    1715       }
    1716       return result
    1717     }
    1718   }
    1719 
    1720   /**
    1721     * 获取对象所有属性
    1722     *
    1723     * @param {Object} obj 对象/数组
    1724     * @return {Array}
    1725     */
    1726   var objectKeys = createGetObjects('keys', 1)
    1727 
    1728   /**
    1729     * 获取对象所有值
    1730     *
    1731     * @param {Object} obj 对象/数组
    1732     * @return {Array}
    1733     */
    1734   var objectValues = createGetObjects('values', 0)
    1735 
    1736   /**
    1737     * 获取对象所有属性、值
    1738     *
    1739     * @param {Object} obj 对象/数组
    1740     * @return {Array}
    1741     */
    1742   var objectEntries = createGetObjects('entries', 2)
    1743 
    1744   function createPickOmit (case1, case2) {
    1745     return function (obj, callback) {
    1746       var item
    1747       var rest = {}
    1748       var result = []
    1749       var context = this
    1750       var args = arguments
    1751       var index = 1
    1752       var len = args.length
    1753       if (!isFunction(callback)) {
    1754         for (callback = 0; index < len; index++) {
    1755           item = args[index]
    1756           if (isArray(item)) {
    1757             result = result.concat(item)
    1758           } else {
    1759             result.push(item)
    1760           }
    1761         }
    1762       }
    1763       each(obj, function (val, key) {
    1764         if ((callback ? callback.call(context, val, key, obj) : findIndexOf(result, function (name) {
    1765           return name === key
    1766         }) > -1) ? case1 : case2) {
    1767           rest[key] = val
    1768         }
    1769       })
    1770       return rest
    1771     }
    1772   }
    1773 
    1774   /**
    1775    * 根据 keys 过滤指定的属性值,返回一个新的对象
    1776    *
    1777    * @param {Object} obj 对象
    1778    * @param {String/Array} keys 键数组
    1779    * @return {Object}
    1780    */
    1781   var pick = createPickOmit(1, 0)
    1782 
    1783   /**
    1784    * 根据 keys 排除指定的属性值,返回一个新的对象
    1785    *
    1786    * @param {Object} obj 对象
    1787    * @param {String/Array} keys 键数组
    1788    * @return {Object}
    1789    */
    1790   var omit = createPickOmit(0, 1)
    1791 
    1792   /**
    1793     * 获取对象第一个值
    1794     *
    1795     * @param {Object} obj 对象/数组
    1796     * @return {Object}
    1797     */
    1798   function getFirst (obj) {
    1799     return objectValues(obj)[0]
    1800   }
    1801 
    1802   /**
    1803     * 获取对象最后一个值
    1804     *
    1805     * @param {Object} obj 对象/数组
    1806     * @return {Object}
    1807     */
    1808   function getLast (obj) {
    1809     var list = objectValues(obj)
    1810     return list[list.length - 1]
    1811   }
    1812 
    1813   function arrayEach (obj, iterate, context) {
    1814     if (obj.forEach) {
    1815       obj.forEach(iterate, context)
    1816     } else {
    1817       for (var index = 0, len = obj.length; index < len; index++) {
    1818         iterate.call(context || this, obj[index], index, obj)
    1819       }
    1820     }
    1821   }
    1822 
    1823   function objectEach (obj, iterate, context) {
    1824     for (var key in obj) {
    1825       if (hasOwnProp(obj, key)) {
    1826         iterate.call(context || this, obj[key], key, obj)
    1827       }
    1828     }
    1829   }
    1830 
    1831   function lastObjectEach (obj, iterate, context) {
    1832     lastArrayEach(objectKeys(obj), function (key) {
    1833       iterate.call(context || this, obj[key], key, obj)
    1834     })
    1835   }
    1836 
    1837   function lastArrayEach (obj, iterate, context) {
    1838     for (var len = obj.length - 1; len >= 0; len--) {
    1839       iterate.call(context || this, obj[len], len, obj)
    1840     }
    1841   }
    1842 
    1843   /**
    1844     * 迭代器,支持 return false 跳出循环 break
    1845     *
    1846     * @param {Object} obj 对象/数组
    1847     * @param {Function} iterate(item, index, obj) 回调
    1848     * @param {Object} context 上下文
    1849     * @return {Object}
    1850     */
    1851   function forOf (obj, iterate, context) {
    1852     if (obj) {
    1853       context = context || this
    1854       if (isArray(obj)) {
    1855         for (var index = 0, len = obj.length; index < len; index++) {
    1856           if (iterate.call(context, obj[index], index, obj) === false) {
    1857             break
    1858           }
    1859         }
    1860       } else {
    1861         for (var key in obj) {
    1862           if (hasOwnProp(obj, key)) {
    1863             if (iterate.call(context, obj[key], key, obj) === false) {
    1864               break
    1865             }
    1866           }
    1867         }
    1868       }
    1869     }
    1870   }
    1871 
    1872   /**
    1873     * 迭代器
    1874     *
    1875     * @param {Object} obj 对象/数组
    1876     * @param {Function} iterate(item, index, obj) 回调
    1877     * @param {Object} context 上下文
    1878     * @return {Object}
    1879     */
    1880   function each (obj, iterate, context) {
    1881     if (obj) {
    1882       context = context || this
    1883       if (isArray(obj)) {
    1884         return arrayEach(obj, iterate, context)
    1885       }
    1886       return objectEach(obj, iterate, context)
    1887     }
    1888     return obj
    1889   }
    1890 
    1891   /**
    1892     * 迭代器,从最后开始迭代
    1893     *
    1894     * @param {Object} obj 对象/数组
    1895     * @param {Function} iterate(item, index, obj) 回调
    1896     * @param {Object} context 上下文
    1897     * @return {Object}
    1898     */
    1899   function lastEach (obj, iterate, context) {
    1900     if (obj) {
    1901       return (isArray(obj) ? lastArrayEach : lastObjectEach)(obj, iterate, context || this)
    1902     }
    1903     return obj
    1904   }
    1905 
    1906   /**
    1907     * 迭代器,从最后开始迭代,支持 return false 跳出循环 break
    1908     *
    1909     * @param {Object} obj 对象/数组
    1910     * @param {Function} iterate(item, index, obj) 回调
    1911     * @param {Object} context 上下文
    1912     * @return {Object}
    1913     */
    1914   function lastForOf (obj, iterate, context) {
    1915     if (obj) {
    1916       var len, list
    1917       context = context || this
    1918       if (isArray(obj)) {
    1919         for (len = obj.length - 1; len >= 0; len--) {
    1920           if (iterate.call(context, obj[len], len, obj) === false) {
    1921             break
    1922           }
    1923         }
    1924       } else {
    1925         list = objectKeys(obj)
    1926         for (len = list.length - 1; len >= 0; len--) {
    1927           if (iterate.call(context, obj[list[len]], list[len], obj) === false) {
    1928             break
    1929           }
    1930         }
    1931       }
    1932     }
    1933   }
    1934 
    1935   function createiterateEmpty (iterate) {
    1936     return function () {
    1937       return isEmpty(iterate)
    1938     }
    1939   }
    1940 
    1941   function getHGSKeys (property) {
    1942     return property ? (isArray(property) ? property : ('' + property).split('.')) : []
    1943   }
    1944 
    1945   /**
    1946    * 检查键、路径是否是该对象的属性
    1947    * @param {Object/Array} data 对象
    1948    * @param {String/Function} property 键、路径
    1949    * @return {Boolean}
    1950    */
    1951   var hgKeyRE = /(.+)?[(d+)]$/
    1952   var sKeyRE = /(.+)[(d+)]$/
    1953   function has (obj, property) {
    1954     if (obj) {
    1955       if (hasOwnProp(obj, property)) {
    1956         return true
    1957       } else {
    1958         var prop, arrIndex, objProp, matchs, rest, isHas
    1959         var keys = getHGSKeys(property)
    1960         var index = 0
    1961         var len = keys.length
    1962         for (rest = obj; index < len; index++) {
    1963           isHas = false
    1964           prop = keys[index]
    1965           matchs = prop ? prop.match(hgKeyRE) : ''
    1966           if (matchs) {
    1967             arrIndex = matchs[1]
    1968             objProp = matchs[2]
    1969             if (arrIndex) {
    1970               if (rest[arrIndex]) {
    1971                 if (hasOwnProp(rest[arrIndex], objProp)) {
    1972                   isHas = true
    1973                   rest = rest[arrIndex][objProp]
    1974                 }
    1975               }
    1976             } else {
    1977               if (hasOwnProp(rest, objProp)) {
    1978                 isHas = true
    1979                 rest = rest[objProp]
    1980               }
    1981             }
    1982           } else {
    1983             if (hasOwnProp(rest, prop)) {
    1984               isHas = true
    1985               rest = rest[prop]
    1986             }
    1987           }
    1988           if (isHas) {
    1989             if (index === len - 1) {
    1990               return true
    1991             }
    1992           } else {
    1993             break
    1994           }
    1995         }
    1996       }
    1997     }
    1998     return false
    1999   }
    2000 
    2001   function valGet (obj, key) {
    2002     var matchs = key ? key.match(hgKeyRE) : ''
    2003     return matchs ? (matchs[1] ? (obj[matchs[1]] ? obj[matchs[1]][matchs[2]] : undefined) : obj[matchs[2]]) : obj[key]
    2004   }
    2005 
    2006   function pathGet (obj, property) {
    2007     if (obj) {
    2008       var rest, keys, len
    2009       var index = 0
    2010       if (hasOwnProp(obj, property)) {
    2011         return obj[property]
    2012       } else {
    2013         keys = getHGSKeys(property)
    2014         len = keys.length
    2015         if (len) {
    2016           for (rest = obj; index < len; index++) {
    2017             rest = valGet(rest, keys[index])
    2018             if (isUndefined(rest) || isNull(rest)) {
    2019               return
    2020             }
    2021           }
    2022         }
    2023         return rest
    2024       }
    2025     }
    2026   }
    2027 
    2028   /**
    2029    * 获取对象的属性的值,如果值为 undefined,则返回默认值
    2030    * @param {Object/Array} data 对象
    2031    * @param {String/Function} property 键、路径
    2032    * @param {Object} defaultValue 默认值
    2033    * @return {Object}
    2034    */
    2035   function get (obj, property, defaultValue) {
    2036     if (isNull(obj) || isUndefined(obj)) {
    2037       return defaultValue
    2038     }
    2039     var result = pathGet(obj, property)
    2040     return isUndefined(result) ? defaultValue : result
    2041   }
    2042 
    2043   function valSet (obj, key, isSet, value) {
    2044     if (obj[key]) {
    2045       if (isSet) {
    2046         obj[key] = value
    2047       }
    2048     } else {
    2049       var index
    2050       var matchs = key ? key.match(sKeyRE) : null
    2051       var rest = isSet ? value : {}
    2052       if (matchs) {
    2053         index = parseInt(matchs[2])
    2054         if (obj[matchs[1]]) {
    2055           obj[matchs[1]][index] = rest
    2056         } else {
    2057           obj[matchs[1]] = new Array(index + 1)
    2058           obj[matchs[1]][index] = rest
    2059         }
    2060       } else {
    2061         obj[key] = rest
    2062       }
    2063       return rest
    2064     }
    2065     return obj[key]
    2066   }
    2067 
    2068   /**
    2069    * 设置对象属性上的值。如果属性不存在则创建它
    2070    * @param {Object/Array} data 对象
    2071    * @param {String/Function} property 键、路径
    2072    * @param {Object} value 值
    2073    */
    2074   function set (obj, property, value) {
    2075     if (obj) {
    2076       var rest = obj
    2077       var keys = getHGSKeys(property)
    2078       var len = keys.length
    2079       arrayEach(keys, function (key, index) {
    2080         rest = valSet(rest, key, index === len - 1, value)
    2081       })
    2082     }
    2083     return obj
    2084   }
    2085 
    2086   /**
    2087     * 集合分组,默认使用键值分组,如果有iterate则使用结果进行分组
    2088     *
    2089     * @param {Array} obj 对象
    2090     * @param {Function} iterate 回调/对象属性
    2091     * @param {Object} context 上下文
    2092     * @return {Object}
    2093     */
    2094   function groupBy (obj, iterate, context) {
    2095     var groupKey
    2096     var result = {}
    2097     if (obj) {
    2098       context = this || context
    2099       if (iterate && isObject(iterate)) {
    2100         iterate = createiterateEmpty(iterate)
    2101       } else if (!isFunction(iterate)) {
    2102         iterate = property(iterate)
    2103       }
    2104       each(obj, function (val, key) {
    2105         groupKey = iterate ? iterate.call(context, val, key, obj) : val
    2106         if (result[groupKey]) {
    2107           result[groupKey].push(val)
    2108         } else {
    2109           result[groupKey] = [val]
    2110         }
    2111       })
    2112     }
    2113     return result
    2114   }
    2115 
    2116   /**
    2117     * 集合分组统计,返回各组中对象的数量统计
    2118     *
    2119     * @param {Array} obj 对象
    2120     * @param {Function} iterate 回调/对象属性
    2121     * @param {Object} context 上下文
    2122     * @return {Object}
    2123     */
    2124   function countBy (obj, iterate, context) {
    2125     var result = groupBy(obj, iterate, context || this)
    2126     objectEach(result, function (item, key) {
    2127       result[key] = item.length
    2128     })
    2129     return result
    2130   }
    2131 
    2132   /**
    2133     * 序号列表生成函数
    2134     *
    2135     * @param {Number} start 起始值
    2136     * @param {Number} stop 结束值
    2137     * @param {Number} step 自增值
    2138     * @return {Object}
    2139     */
    2140   function range (start, stop, step) {
    2141     var index, len
    2142     var result = []
    2143     var args = arguments
    2144     if (args.length < 2) {
    2145       stop = args[0]
    2146       start = 0
    2147     }
    2148     index = start >> 0
    2149     len = stop >> 0
    2150     if (index < stop) {
    2151       step = step >> 0 || 1
    2152       for (; index < len; index += step) {
    2153         result.push(index)
    2154       }
    2155     }
    2156     return result
    2157   }
    2158 
    2159   /**
    2160     * 创建一个策略函数,当被重复调用函数的时候,至少每隔多少秒毫秒调用一次该函数
    2161     *
    2162     * @param {Function} callback 回调
    2163     * @param {Number} wait 多少秒毫
    2164     * @param {Object} options 参数{leading: 是否在之前执行, trailing: 是否在之后执行}
    2165     * @return {Function}
    2166     */
    2167   function throttle (callback, wait, options) {
    2168     var args, context
    2169     var opts = options || {}
    2170     var runFlag = false
    2171     var timeout = 0
    2172     var optLeading = 'leading' in opts ? opts.leading : true
    2173     var optTrailing = 'trailing' in opts ? opts.trailing : false
    2174     var runFn = function () {
    2175       runFlag = true
    2176       callback.apply(context, args)
    2177       timeout = setTimeout(endFn, wait)
    2178     }
    2179     var endFn = function () {
    2180       timeout = 0
    2181       if (!runFlag && optTrailing === true) {
    2182         runFn()
    2183       }
    2184     }
    2185     var cancelFn = function () {
    2186       var rest = timeout !== 0
    2187       clearTimeout(timeout)
    2188       runFlag = false
    2189       timeout = 0
    2190       return rest
    2191     }
    2192     var throttled = function () {
    2193       args = arguments
    2194       context = this
    2195       runFlag = false
    2196       if (timeout === 0) {
    2197         if (optLeading === true) {
    2198           runFn()
    2199         } else if (optTrailing === true) {
    2200           timeout = setTimeout(endFn, wait)
    2201         }
    2202       }
    2203     }
    2204     throttled.cancel = cancelFn
    2205     return throttled
    2206   }
    2207 
    2208   /**
    2209     * 创建一个防反跳策略函数,在函数最后一次调用多少毫秒之后才会再次执行,如果在期间内重复调用会重新计算延迟
    2210     *
    2211     * @param {Function} callback 回调
    2212     * @param {Number} wait 多少秒毫
    2213     * @param {Object} options 参数{leading: 是否在之前执行, trailing: 是否在之后执行}
    2214     * @return {Function}
    2215     */
    2216   function debounce (callback, wait, options) {
    2217     var args, context
    2218     var opts = options || {}
    2219     var runFlag = false
    2220     var timeout = 0
    2221     var isLeading = typeof options === 'boolean'
    2222     var optLeading = 'leading' in opts ? opts.leading : isLeading
    2223     var optTrailing = 'trailing' in opts ? opts.trailing : !isLeading
    2224     var clearTimeoutFn = clearTimeout
    2225     var runFn = function () {
    2226       runFlag = true
    2227       timeout = 0
    2228       callback.apply(context, args)
    2229     }
    2230     var endFn = function () {
    2231       if (optLeading === true) {
    2232         timeout = 0
    2233       }
    2234       if (!runFlag && optTrailing === true) {
    2235         runFn()
    2236       }
    2237     }
    2238     var cancelFn = function () {
    2239       var rest = timeout !== 0
    2240       clearTimeoutFn(timeout)
    2241       timeout = 0
    2242       return rest
    2243     }
    2244     var debounced = function () {
    2245       runFlag = false
    2246       args = arguments
    2247       context = this
    2248       if (timeout === 0) {
    2249         if (optLeading === true) {
    2250           runFn()
    2251         }
    2252       } else {
    2253         clearTimeoutFn(timeout)
    2254       }
    2255       timeout = setTimeout(endFn, wait)
    2256     }
    2257     debounced.cancel = cancelFn
    2258     return debounced
    2259   }
    2260 
    2261   var baseExports = {
    2262     _hasOwnProp: hasOwnProp,
    2263     isNaN: isNaN,
    2264     isFinite: isNumberFinite,
    2265     isUndefined: isUndefined,
    2266     isArray: isArray,
    2267     isFloat: isFloat,
    2268     isInteger: isInteger,
    2269     isFunction: isFunction,
    2270     isBoolean: isBoolean,
    2271     isString: isString,
    2272     isNumber: isNumber,
    2273     isRegExp: isRegExp,
    2274     isObject: isObject,
    2275     isPlainObject: isPlainObject,
    2276     isDate: isDate,
    2277     isError: isError,
    2278     isTypeError: isTypeError,
    2279     isEmpty: isEmpty,
    2280     isNull: isNull,
    2281     isSymbol: isSymbol,
    2282     isArguments: isArguments,
    2283     isElement: isElement,
    2284     isDocument: isDocument,
    2285     isWindow: isWindow,
    2286     isFormData: isFormData,
    2287     isMap: isMap,
    2288     isWeakMap: isWeakMap,
    2289     isSet: isSet,
    2290     isWeakSet: isWeakSet,
    2291     isLeapYear: isLeapYear,
    2292     isMatch: isMatch,
    2293     isEqual: isEqual,
    2294     isEqualWith: isEqualWith,
    2295     property: property,
    2296     getType: getType,
    2297     uniqueId: uniqueId,
    2298     getSize: getSize,
    2299     slice: arraySlice,
    2300     indexOf: indexOf,
    2301     lastIndexOf: lastIndexOf,
    2302     findIndexOf: findIndexOf,
    2303     findLastIndexOf: findLastIndexOf,
    2304     includes: includes,
    2305     contains: includes,
    2306     assign: objectAssign,
    2307     extend: objectAssign,
    2308     toStringJSON: toStringJSON,
    2309     toJSONString: toJSONString,
    2310     keys: objectKeys,
    2311     values: objectValues,
    2312     entries: objectEntries,
    2313     pick: pick,
    2314     omit: omit,
    2315     first: getFirst,
    2316     last: getLast,
    2317     each: each,
    2318     forOf: forOf,
    2319     arrayEach: arrayEach,
    2320     forEach: arrayEach,
    2321     objectEach: objectEach,
    2322     lastForOf: lastForOf,
    2323     lastEach: lastEach,
    2324     lastForEach: lastArrayEach,
    2325     lastArrayEach: lastArrayEach,
    2326     lastObjectEach: lastObjectEach,
    2327     has: has,
    2328     get: get,
    2329     set: set,
    2330     groupBy: groupBy,
    2331     countBy: countBy,
    2332     objectMap: objectMap,
    2333     clone: clone,
    2334     delay: delay,
    2335     bind: bind,
    2336     once: once,
    2337     after: after,
    2338     before: before,
    2339     clear: clearObject,
    2340     remove: removeObject,
    2341     range: range,
    2342     throttle: throttle,
    2343     debounce: debounce,
    2344     destructuring: destructuring
    2345   }
    2346 
    2347   /* eslint-disable valid-typeof */
    2348   function isBrowseStorage (storage) {
    2349     try {
    2350       var testKey = '__xe_t'
    2351       storage.setItem(testKey, 1)
    2352       storage.removeItem(testKey)
    2353       return true
    2354     } catch (e) {
    2355       return false
    2356     }
    2357   }
    2358 
    2359   function isBrowseType (type) {
    2360     return navigator.userAgent.indexOf(type) > -1
    2361   }
    2362 
    2363   /**
    2364     * 获取浏览器内核
    2365     * @return Object
    2366     */
    2367   function browse () {
    2368     var $body, $dom, isChrome, isEdge
    2369     var isMobile = false
    2370     var strUndefined = 'undefined'
    2371     var result = {
    2372       isNode: false,
    2373       isMobile: isMobile,
    2374       isPC: false,
    2375       isDoc: typeof document !== strUndefined
    2376     }
    2377     if (typeof window === strUndefined && typeof process !== strUndefined) {
    2378       result.isNode = true
    2379     } else {
    2380       isEdge = isBrowseType('Edge')
    2381       isChrome = isBrowseType('Chrome')
    2382       isMobile = /(Android|webOS|iPhone|iPad|iPod|SymbianOS|BlackBerry|Windows Phone)/.test(navigator.userAgent)
    2383       if (result.isDoc) {
    2384         $dom = document
    2385         $body = $dom.body || $dom.documentElement
    2386         baseExports.each(['webkit', 'khtml', 'moz', 'ms', 'o'], function (core) {
    2387           result['-' + core] = !!$body[core + 'MatchesSelector']
    2388         })
    2389       }
    2390       baseExports.assign(result, {
    2391         edge: isEdge,
    2392         msie: !isEdge && result['-ms'],
    2393         safari: !isChrome && !isEdge && isBrowseType('Safari'),
    2394         isMobile: isMobile,
    2395         isPC: !isMobile,
    2396         isLocalStorage: isBrowseStorage(window.localStorage),
    2397         isSessionStorage: isBrowseStorage(window.sessionStorage)
    2398       })
    2399     }
    2400     return result
    2401   }
    2402 
    2403   var browseExports = {
    2404     browse: browse
    2405   }
    2406 
    2407   var isBowseDoc = typeof document !== 'undefined'
    2408 
    2409   function toCookieUnitTime (unit, expires) {
    2410     var num = parseFloat(expires)
    2411     var nowdate = new Date()
    2412     var time = nowdate.getTime()
    2413     switch (unit) {
    2414       case 'y': return dateExports.getWhatYear(nowdate, num).getTime()
    2415       case 'M': return dateExports.getWhatMonth(nowdate, num).getTime()
    2416       case 'd': return dateExports.getWhatDay(nowdate, num).getTime()
    2417       case 'h':
    2418       case 'H': return time + num * 60 * 60 * 1000
    2419       case 'm': return time + num * 60 * 1000
    2420       case 's': return time + num * 1000
    2421     }
    2422     return time
    2423   }
    2424 
    2425   function toCookieUTCString (date) {
    2426     return (baseExports.isDate(date) ? date : new Date(date)).toUTCString()
    2427   }
    2428 
    2429   /**
    2430     * cookie操作函数
    2431     * @param {String/Array/Object} name 键/数组/对象
    2432     * @param {String} value 值
    2433     * @param {Object} options 参数
    2434     *   @param {String} name: 键
    2435     *   @param {Object} value: 值
    2436     *   @param {String} path: 路径
    2437     *   @param {String} domain: 作用域
    2438     *   @param {Boolean} secure: 设置为安全的,只能用https协议
    2439     *   @param {Number} expires: 过期时间,可以指定日期或者字符串,默认天
    2440     */
    2441   function cookie (name, value, options) {
    2442     if (isBowseDoc) {
    2443       var opts, expires, values, result, cookies, keyIndex
    2444       var inserts = []
    2445       var args = arguments
    2446       var decode = decodeURIComponent
    2447       var encode = encodeURIComponent
    2448       var $dom = document
    2449       var arrayEach = baseExports.each
    2450       var objectAssign = baseExports.assign
    2451       var isObject = baseExports.isObject
    2452       if (this && this.$context) {
    2453         this.$context = null
    2454       }
    2455       if (baseExports.isArray(name)) {
    2456         inserts = name
    2457       } else if (args.length > 1) {
    2458         inserts = [objectAssign({ name: name, value: value }, options)]
    2459       } else if (isObject(name)) {
    2460         inserts = [name]
    2461       }
    2462       if (inserts.length > 0) {
    2463         arrayEach(inserts, function (obj) {
    2464           opts = objectAssign({}, setupDefaults.cookies, obj)
    2465           values = []
    2466           if (opts.name) {
    2467             expires = opts.expires
    2468             values.push(encode(opts.name) + '=' + encode(isObject(opts.value) ? JSON.stringify(opts.value) : opts.value))
    2469             if (expires) {
    2470               if (isNaN(expires)) {
    2471                 // UTCString || Unit
    2472                 expires = expires.replace(/^([0-9]+)(y|M|d|H|h|m|s)$/, function (text, num, unit) {
    2473                   return toCookieUTCString(toCookieUnitTime(unit, num))
    2474                 })
    2475               } else if (/^[0-9]{11,13}$/.test(expires) || baseExports.isDate(expires)) {
    2476                 // Date || now
    2477                 expires = toCookieUTCString(expires)
    2478               } else {
    2479                 // day
    2480                 expires = toCookieUTCString(toCookieUnitTime('d', expires))
    2481               }
    2482               opts.expires = expires
    2483             }
    2484             arrayEach(['expires', 'path', 'domain', 'secure'], function (key) {
    2485               if (opts[key] !== undefined) {
    2486                 values.push(opts[key] && key === 'secure' ? key : (key + '=' + opts[key]))
    2487               }
    2488             })
    2489           }
    2490           $dom.cookie = values.join('; ')
    2491         })
    2492         return true
    2493       } else {
    2494         result = {}
    2495         cookies = $dom.cookie
    2496         if (cookies) {
    2497           arrayEach(cookies.split('; '), function (val) {
    2498             keyIndex = val.indexOf('=')
    2499             result[decode(val.substring(0, keyIndex))] = decode(val.substring(keyIndex + 1) || '')
    2500           })
    2501         }
    2502         return args.length === 1 ? result[name] : result
    2503       }
    2504     }
    2505     return false
    2506   }
    2507 
    2508   function isCookieKey (key) {
    2509     return baseExports.includes(cookieKeys(), key)
    2510   }
    2511 
    2512   function setCookieItem (name, key, options) {
    2513     cookie(name, key, options)
    2514     return cookie
    2515   }
    2516 
    2517   function removeCookieItem (name, options) {
    2518     cookie(name, 0, baseExports.assign({ expires: -1 }, setupDefaults.cookies, options))
    2519   }
    2520 
    2521   function cookieKeys () {
    2522     return baseExports.keys(cookie())
    2523   }
    2524 
    2525   baseExports.assign(cookie, {
    2526     _c: false,
    2527     isKey: isCookieKey,
    2528     set: setCookieItem,
    2529     setItem: setCookieItem,
    2530     get: cookie,
    2531     getItem: cookie,
    2532     remove: removeCookieItem,
    2533     removeItem: removeCookieItem,
    2534     keys: cookieKeys,
    2535     getJSON: cookie
    2536   })
    2537 
    2538   var cookieExports = {
    2539     cookie: cookie
    2540   }
    2541 
    2542   var DAY_TIME = 86400000
    2543   var WEEK_TIME = DAY_TIME * 7
    2544   var STRING_FIRST = 'first'
    2545   var STRING_LAST = 'last'
    2546 
    2547   /**
    2548    * 返回当前时间戳
    2549    *
    2550    * @returns Number
    2551    */
    2552   var now = Date.now || function () {
    2553     return getDateTime(new Date())
    2554   }
    2555 
    2556   /**
    2557    * 将日期格式化为时间戳
    2558    *
    2559     * @param {String/Number/Date} str 日期或数字
    2560     * @param {String} format 解析日期格式
    2561    * @returns Number
    2562    */
    2563   var timestamp = function (str, format) {
    2564     if (arguments.length) {
    2565       var date = toStringDate(str, format)
    2566       return baseExports.isDate(date) ? getDateTime(date) : date
    2567     }
    2568     return now()
    2569   }
    2570 
    2571   var dateFormatRules = [
    2572     { rules: [['yyyy', 4], ['yy', 2]] },
    2573     { rules: [['MM', 2], ['M', 1]], offset: -1 },
    2574     { rules: [['dd', 2], ['d', 1]] },
    2575     { rules: [['HH', 2], ['H', 1]] },
    2576     { rules: [['mm', 2], ['m', 1]] },
    2577     { rules: [['ss', 2], ['s', 1]] },
    2578     { rules: [['SSS', 3], ['SS', 2], ['S', 1]] },
    2579     { rules: [['ZZ', 5], ['Z', 6]] }
    2580   ]
    2581 
    2582   function getDateTime (date) {
    2583     return date.getTime()
    2584   }
    2585 
    2586   function _utcDateTime (dates) {
    2587     return Date.UTC(dates[0], dates[1], dates[2], dates[3], dates[4], dates[5], dates[6])
    2588   }
    2589 
    2590   function _dateFullYear (date) {
    2591     return date.getFullYear()
    2592   }
    2593 
    2594   function _dateMonth (date) {
    2595     return date.getMonth()
    2596   }
    2597 
    2598   function getYMD (date) {
    2599     return new Date(_dateFullYear(date), _dateMonth(date), date.getDate())
    2600   }
    2601 
    2602   function getYMDTime (date) {
    2603     return getDateTime(getYMD(date))
    2604   }
    2605 
    2606   /**
    2607    * 比较两个日期
    2608    *
    2609    * @param {Number/String/Date} date1 日期
    2610    * @param {Number/String/Date} date2 日期
    2611    * @param {String} format 格式化
    2612    */
    2613   function isDateSame (date1, date2, format) {
    2614     if (date1 && date2) {
    2615       return toDateString(date1, format) === toDateString(date2, format)
    2616     }
    2617     return false
    2618   }
    2619 
    2620   /**
    2621     * 字符串转为日期
    2622     *
    2623     * @param {String/Number/Date} str 日期或数字
    2624     * @param {String} format 解析日期格式(yyyy年份、MM月份、dd天、hh(12)HH(24)小时、mm分钟、ss秒、SSS毫秒、Z时区)
    2625     * @return {String}
    2626     */
    2627   function toStringDate (str, format) {
    2628     var arr, sIndex, index, rules, len, rest, isDate, tempMatch, zStr
    2629     var dates = []
    2630     if (str) {
    2631       isDate = baseExports.isDate(str)
    2632       if (isDate || /^[0-9]{11,13}$/.test(str)) {
    2633         rest = new Date(isDate ? getDateTime(str) : Number(str))
    2634       } else if (baseExports.isString(str)) {
    2635         format = format || setupDefaults.formatDate
    2636         baseExports.each(dateFormatRules, function (item) {
    2637           for (index = 0, rules = item.rules, len = rules.length; index < len; index++) {
    2638             arr = rules[index]
    2639             sIndex = format.indexOf(arr[0])
    2640             if (sIndex > -1) {
    2641               tempMatch = str.substring(sIndex, sIndex + arr[1]) || 0
    2642               if (item.offset) {
    2643                 tempMatch = parseFloat(tempMatch) + item.offset
    2644               }
    2645               dates.push(tempMatch)
    2646               break
    2647             } else if (index === len - 1) {
    2648               dates.push(0)
    2649             }
    2650           }
    2651         })
    2652         zStr = dates[7]
    2653         // 解析时区
    2654         if (zStr) {
    2655           // 如果为UTC 时间
    2656           if (zStr[0] === 'z' || zStr[0] === 'Z') {
    2657             rest = new Date(_utcDateTime(dates))
    2658           } else {
    2659             // 如果指定时区,时区转换
    2660             tempMatch = zStr.match(/([-+]{1})(d{2}):?(d{2})/)
    2661             if (tempMatch) {
    2662               rest = new Date(_utcDateTime(dates) - (tempMatch[1] === '-' ? -1 : 1) * parseInt(tempMatch[2]) * 3600000 + parseInt(tempMatch[3]) * 60000)
    2663             }
    2664           }
    2665         } else {
    2666           rest = new Date(dates[0], dates[1], dates[2], dates[3], dates[4], dates[5], dates[6])
    2667         }
    2668       }
    2669     }
    2670     return !rest || isNaN(getDateTime(rest)) ? 'Invalid Date' : rest
    2671   }
    2672 
    2673   function handleCustomTemplate (date, formats, match, value) {
    2674     var format = formats[match]
    2675     if (format) {
    2676       if (baseExports.isFunction(format)) {
    2677         return format(value, match, date)
    2678       } else {
    2679         return format[value]
    2680       }
    2681     }
    2682     return value
    2683   }
    2684 
    2685   function formatPadStart (str, len, padStr) {
    2686     str = '' + str
    2687     var index = str.length
    2688     while (index < len) {
    2689       str = padStr + str
    2690       index++
    2691     }
    2692     return str
    2693   }
    2694 
    2695   /**
    2696     * 日期格式化为字符串
    2697     *
    2698     * @param {Date} date 日期或数字
    2699     * @param {String} format 输出日期格式(年份(yy|yyyy)、月份(M|MM自动补0)、天(d|dd自动补0)、12小时制(h|hh自动补0)、24小时制(H|HH自动补0)、分钟(m|mm自动补0)、秒(s|ss自动补0)、毫秒(S|SSS自动补0)、D当年的第几天、a/A上午下午、e/E星期几、w当年的第几周、W当月的第几周、q当年第几个季度、Z时区)
    2700     * @param {Object} options {formats: {q: ['日', '一', '二', '三', '四', '五', '六'], E: function (value, match, date) {return '三'}, }} 自定义格式化模板
    2701     * @return {String}
    2702     */
    2703   function toDateString (date, format, options) {
    2704     if (date) {
    2705       date = toStringDate(date)
    2706       if (baseExports.isDate(date)) {
    2707         var result = format || setupDefaults.formatString
    2708         var hours = date.getHours()
    2709         var apm = hours < 12 ? 'am' : 'pm'
    2710         var zoneHours = date.getTimezoneOffset() / 60 * -1
    2711         var formats = baseExports.assign({}, setupDefaults.formatStringMatchs, options ? options.formats : null)
    2712         var timeRules = [
    2713           [/y{2,4}/g, '', function (match) { return ('' + _dateFullYear(date)).substr(4 - match.length) }],
    2714           [/M{1,2}/g, _dateMonth(date) + 1],
    2715           [/d{1,2}/g, date.getDate()],
    2716           [/H{1,2}/g, hours],
    2717           [/h{1,2}/g, hours <= 12 ? hours : hours - 12],
    2718           [/m{1,2}/g, date.getMinutes()],
    2719           [/s{1,2}/g, date.getSeconds()],
    2720           [/S{1,3}/g, date.getMilliseconds()],
    2721           [/a/g, '', function (match) { return handleCustomTemplate(date, formats, match, apm) }],
    2722           [/A/g, '', function (match) { return handleCustomTemplate(date, formats, match, apm.toLocaleUpperCase()) }],
    2723           [/e/g, '', function (match) { return handleCustomTemplate(date, formats, match, date.getDay() - 1) }],
    2724           [/E/g, '', function (match) { return handleCustomTemplate(date, formats, match, date.getDay()) }],
    2725           [/q/g, '', function (match) { return handleCustomTemplate(date, formats, match, Math.floor((_dateMonth(date) + 3) / 3)) }],
    2726           [/Z{1,2}/g, '', function (match) { return handleCustomTemplate(date, formats, match, (zoneHours >= 0 ? '+' : '-') + formatPadStart(zoneHours, 2, '0') + (match.length === 1 ? ':' : '') + '00') }],
    2727           [/W{1,2}/g, '', function (match) { return formatPadStart(handleCustomTemplate(date, formats, match, getYearWeek(date)), match.length, '0') }],
    2728           [/D{1,3}/g, '', function (match) { return formatPadStart(handleCustomTemplate(date, formats, match, getYearDay(date)), match.length, '0') }]
    2729         ]
    2730         var item
    2731         var index = 0
    2732         var len = timeRules.length
    2733         for (; index < len; index++) {
    2734           item = timeRules[index]
    2735           result = result.replace(item[0], item[2] || function (match) {
    2736             return formatPadStart(item[1], match.length, '0')
    2737           })
    2738         }
    2739         return result
    2740       }
    2741       return date
    2742     }
    2743     return ''
    2744   }
    2745 
    2746   /**
    2747     * 返回前几年或后几年的日期
    2748     *
    2749     * @param {Date} date 日期或数字
    2750     * @param {Number} year 年(默认当前年)、前几个年(数值)、后几个年(数值)
    2751     * @param {Number/String} month 获取哪月(null默认当前年)、年初(first)、年末(last)、指定月份(0-11)
    2752     * @return {Date}
    2753     */
    2754   function getWhatYear (date, year, month) {
    2755     var number
    2756     date = toStringDate(date)
    2757     if (baseExports.isDate(date)) {
    2758       if (year) {
    2759         number = year && !isNaN(year) ? year : 0
    2760         date.setFullYear(_dateFullYear(date) + number)
    2761       }
    2762       if (month || !isNaN(month)) {
    2763         if (month === STRING_FIRST) {
    2764           return new Date(_dateFullYear(date), 0, 1)
    2765         } else if (month === STRING_LAST) {
    2766           date.setMonth(11)
    2767           return getWhatMonth(date, 0, STRING_LAST)
    2768         } else {
    2769           date.setMonth(month)
    2770         }
    2771       }
    2772     }
    2773     return date
    2774   }
    2775 
    2776   /**
    2777     * 返回前几月或后几月的日期
    2778     *
    2779     * @param {Date} date 日期或数字
    2780     * @param {Number} month 月(默认当前月)、前几个月、后几个月
    2781     * @param {Number/String} day 获取哪天(null默认当前天)、月初(first)、月末(last)、指定天数(数值)
    2782     * @return {Date}
    2783     */
    2784   function getWhatMonth (date, month, day) {
    2785     var monthOffset = month && !isNaN(month) ? month : 0
    2786     date = toStringDate(date)
    2787     if (baseExports.isDate(date)) {
    2788       if (day || !isNaN(day)) {
    2789         if (day === STRING_FIRST) {
    2790           return new Date(_dateFullYear(date), _dateMonth(date) + monthOffset, 1)
    2791         } else if (day === STRING_LAST) {
    2792           return new Date(getDateTime(getWhatMonth(date, monthOffset + 1, STRING_FIRST)) - 1)
    2793         } else {
    2794           date.setDate(day)
    2795         }
    2796       }
    2797       if (monthOffset) {
    2798         date.setMonth(_dateMonth(date) + monthOffset)
    2799       }
    2800     }
    2801     return date
    2802   }
    2803 
    2804   /**
    2805     * 返回前几周或后几周的星期几
    2806     *
    2807     * @param {Date} date 日期
    2808     * @param {Number} week 周(默认当前周)、前几周、后几周
    2809     * @param {Number} day 星期天(默认0)、星期一(1)、星期二(2)、星期三(3)、星期四(4)、星期五(5)、星期六(6)
    2810     * @return {Date}
    2811     */
    2812   function getWhatWeek (date, week, day) {
    2813     var time, whatDayTime, currentDay, customDay
    2814     date = toStringDate(date)
    2815     if (baseExports.isDate(date)) {
    2816       customDay = Number(/^[0-7]$/.test(day) ? day : date.getDay())
    2817       currentDay = date.getDay()
    2818       time = getDateTime(date)
    2819       whatDayTime = time + ((customDay === 0 ? 7 : customDay) - (currentDay === 0 ? 7 : currentDay)) * DAY_TIME
    2820       if (week && !isNaN(week)) {
    2821         whatDayTime += week * WEEK_TIME
    2822       }
    2823       return new Date(whatDayTime)
    2824     }
    2825     return date
    2826   }
    2827 
    2828   /**
    2829     * 返回前几天或后几天的日期
    2830     *
    2831     * @param {Date} date 日期或数字
    2832     * @param {Number} day 天(默认当天)、前几天、后几天
    2833     * @param {String} mode 获取时分秒(null默认当前时分秒)、日初(first)、日末(last)
    2834     * @return {Date}
    2835     */
    2836   function getWhatDay (date, day, mode) {
    2837     date = toStringDate(date)
    2838     if (baseExports.isDate(date) && !isNaN(day)) {
    2839       date.setDate(date.getDate() + Number(day))
    2840       if (mode === STRING_FIRST) {
    2841         return new Date(_dateFullYear(date), _dateMonth(date), date.getDate())
    2842       } else if (mode === STRING_LAST) {
    2843         return new Date(getDateTime(getWhatDay(date, 1, STRING_FIRST)) - 1)
    2844       }
    2845     }
    2846     return date
    2847   }
    2848 
    2849   /**
    2850     * 返回某个月的第几周
    2851     *
    2852     * @param {Date} date 日期或数字
    2853     * @return {Number}
    2854     */
    2855   function getMonthWeek (date) {
    2856     var monthFirst, monthFirstWeek
    2857     var currentDate = toStringDate(date)
    2858     if (baseExports.isDate(currentDate)) {
    2859       monthFirst = getWhatMonth(currentDate, 0, STRING_FIRST)
    2860       monthFirstWeek = getWhatWeek(monthFirst, 0, 1)
    2861       if (monthFirstWeek < monthFirst) {
    2862         monthFirstWeek = getWhatWeek(monthFirst, 1, 1)
    2863       }
    2864       if (currentDate >= monthFirstWeek) {
    2865         return Math.floor((getYMDTime(currentDate) - getYMDTime(monthFirstWeek)) / WEEK_TIME) + 1
    2866       }
    2867       return getMonthWeek(getWhatWeek(currentDate, 0, 1))
    2868     }
    2869     return currentDate
    2870   }
    2871 
    2872   /**
    2873     * 返回某个年份的第几天
    2874     *
    2875     * @param {Date} date 日期或数字
    2876     * @return {Number}
    2877     */
    2878   function getYearDay (date) {
    2879     date = toStringDate(date)
    2880     if (baseExports.isDate(date)) {
    2881       return Math.floor((getYMDTime(date) - getYMDTime(getWhatYear(date, 0, STRING_FIRST))) / DAY_TIME) + 1
    2882     }
    2883     return date
    2884   }
    2885 
    2886   /**
    2887     * 返回某个年份的第几周
    2888     *
    2889     * @param {Date} date 日期或数字
    2890     * @return {Number}
    2891     */
    2892   function getYearWeek (date) {
    2893     date = toStringDate(date)
    2894     if (baseExports.isDate(date)) {
    2895       date.setHours(0, 0, 0, 0)
    2896       date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7)
    2897       var week = new Date(date.getFullYear(), 0, 4)
    2898       return Math.round(((date.getTime() - week.getTime()) / DAY_TIME + (week.getDay() + 6) % 7 - 3) / 7) + 1
    2899     }
    2900     return date
    2901   }
    2902 
    2903   /**
    2904     * 返回某个年份的天数
    2905     *
    2906     * @param {Date} date 日期或数字
    2907     * @param {Number} year 年(默认当年)、前几个年、后几个年
    2908     * @return {Number}
    2909     */
    2910   function getDayOfYear (date, year) {
    2911     date = toStringDate(date)
    2912     if (baseExports.isDate(date)) {
    2913       return baseExports.isLeapYear(getWhatYear(date, year)) ? 366 : 365
    2914     }
    2915     return date
    2916   }
    2917 
    2918   /**
    2919     * 返回某个月份的天数
    2920     *
    2921     * @param {Date} date 日期或数字
    2922     * @param {Number} month 月(默认当月)、前几个月、后几个月
    2923     * @return {Number}
    2924     */
    2925   function getDayOfMonth (date, month) {
    2926     date = toStringDate(date)
    2927     if (baseExports.isDate(date)) {
    2928       return Math.floor((getDateTime(getWhatMonth(date, month, STRING_LAST)) - getDateTime(getWhatMonth(date, month, STRING_FIRST))) / DAY_TIME) + 1
    2929     }
    2930     return date
    2931   }
    2932 
    2933   /**
    2934     * 返回两个日期之间差距,如果结束日期小于开始日期done为fasle
    2935     *
    2936     * @param {Date} startDate 开始日期
    2937     * @param {Date} endDate 结束日期或当期日期
    2938     * @param {Date} rule 自定义计算规则
    2939     * @return {Object}
    2940     */
    2941   function getDateDiff (startDate, endDate, rules) {
    2942     var startTime, endTime, item, diffTime, rule, len, index
    2943     var result = { done: false, time: 0 }
    2944     startDate = toStringDate(startDate)
    2945     endDate = endDate ? toStringDate(endDate) : new Date()
    2946     if (baseExports.isDate(startDate) && baseExports.isDate(endDate)) {
    2947       startTime = getDateTime(startDate)
    2948       endTime = getDateTime(endDate)
    2949       if (startTime < endTime) {
    2950         diffTime = result.time = endTime - startTime
    2951         rule = rules && rules.length > 0 ? rules : setupDefaults.dateDiffRules
    2952         result.done = true
    2953         for (index = 0, len = rule.length; index < len; index++) {
    2954           item = rule[index]
    2955           if (diffTime >= item[1]) {
    2956             if (index === len - 1) {
    2957               result[item[0]] = diffTime || 0
    2958             } else {
    2959               result[item[0]] = Math.floor(diffTime / item[1])
    2960               diffTime -= result[item[0]] * item[1]
    2961             }
    2962           } else {
    2963             result[item[0]] = 0
    2964           }
    2965         }
    2966       }
    2967     }
    2968     return result
    2969   }
    2970 
    2971   var dateExports = {
    2972     now: now,
    2973     timestamp: timestamp,
    2974     isDateSame: isDateSame,
    2975     toStringDate: toStringDate,
    2976     toDateString: toDateString,
    2977     getWhatYear: getWhatYear,
    2978     getWhatMonth: getWhatMonth,
    2979     getWhatWeek: getWhatWeek,
    2980     getWhatDay: getWhatDay,
    2981     getYearDay: getYearDay,
    2982     getYearWeek: getYearWeek,
    2983     getMonthWeek: getMonthWeek,
    2984     getDayOfYear: getDayOfYear,
    2985     getDayOfMonth: getDayOfMonth,
    2986     getDateDiff: getDateDiff
    2987   }
    2988 
    2989   var $locat = typeof location === 'undefined' ? 0 : location
    2990   var decode = decodeURIComponent
    2991   var encode = encodeURIComponent
    2992 
    2993   function parseURLQuery (uri) {
    2994     return parseParams(uri.split('?')[1] || '')
    2995   }
    2996 
    2997   /**
    2998    * 查询参数序列化
    2999    *
    3000    * @param {String} query 反序列化的字符串
    3001    */
    3002   function parseParams (str) {
    3003     var items
    3004     var result = {}
    3005     if (str && baseExports.isString(str)) {
    3006       baseExports.each(str.split('&'), function (param) {
    3007         items = param.split('=')
    3008         result[decode(items[0])] = decode(items[1] || '')
    3009       })
    3010     }
    3011     return result
    3012   }
    3013 
    3014   function stringifyParams (resultVal, resultKey, isArr) {
    3015     var _arr
    3016     var result = []
    3017     baseExports.each(resultVal, function (item, key) {
    3018       _arr = baseExports.isArray(item)
    3019       if (baseExports.isPlainObject(item) || _arr) {
    3020         result = result.concat(stringifyParams(item, resultKey + '[' + key + ']', _arr))
    3021       } else {
    3022         result.push(encode(resultKey + '[' + (isArr ? '' : key) + ']') + '=' + encode(item === null ? '' : item))
    3023       }
    3024     })
    3025     return result
    3026   }
    3027 
    3028   function getLocatOrigin () {
    3029     return $locat ? ($locat.origin || ($locat.protocol + '//' + $locat.host)) : ''
    3030   }
    3031 
    3032   function getBaseURL () {
    3033     if ($locat) {
    3034       var pathname = $locat.pathname
    3035       var lastIndex = baseExports.lastIndexOf(pathname, '/') + 1
    3036       return getLocatOrigin() + (lastIndex === pathname.length ? pathname : pathname.substring(0, lastIndex))
    3037     }
    3038     return ''
    3039   }
    3040 
    3041   function parseUrl (url) {
    3042     var hashs, portText, searchs, parsed
    3043     var href = '' + url
    3044     if (href.indexOf('//') === 0) {
    3045       href = ($locat ? $locat.protocol : '') + href
    3046     } else if (href.indexOf('/') === 0) {
    3047       href = getLocatOrigin() + href
    3048     }
    3049     searchs = href.replace(/#.*/, '').match(/(?.*)/)
    3050     parsed = {
    3051       href: href,
    3052       hash: '',
    3053       host: '',
    3054       hostname: '',
    3055       protocol: '',
    3056       port: '',
    3057       search: searchs && searchs[1] && searchs[1].length > 1 ? searchs[1] : ''
    3058     }
    3059     parsed.path = href.replace(/^([a-z0-9.+-]*:)///, function (text, protocol) {
    3060       parsed.protocol = protocol
    3061       return ''
    3062     }).replace(/^([a-z0-9.+-]*)(:d+)?/?/, function (text, hostname, port) {
    3063       portText = port || ''
    3064       parsed.port = portText.replace(':', '')
    3065       parsed.hostname = hostname
    3066       parsed.host = hostname + portText
    3067       return '/'
    3068     }).replace(/(#.*)/, function (text, hash) {
    3069       parsed.hash = hash.length > 1 ? hash : ''
    3070       return ''
    3071     })
    3072     hashs = parsed.hash.match(/#((.*)?|(.*))/)
    3073     parsed.pathname = parsed.path.replace(/(?|#.*).*/, '')
    3074     parsed.origin = parsed.protocol + '//' + parsed.host
    3075     parsed.hashKey = hashs ? (hashs[2] || hashs[1] || '') : ''
    3076     parsed.hashQuery = parseURLQuery(parsed.hash)
    3077     parsed.searchQuery = parseURLQuery(parsed.search)
    3078     return parsed
    3079   }
    3080 
    3081   /**
    3082     * 获取地址栏信息
    3083     *
    3084     * @return Object
    3085     */
    3086   function locat () {
    3087     return $locat ? parseUrl($locat.href) : {}
    3088   }
    3089 
    3090   /**
    3091    * 查询参数序列化
    3092    *
    3093    * @param {Object} query 序列化的对象
    3094    */
    3095   function serialize (query) {
    3096     var _arr
    3097     var params = []
    3098     baseExports.each(query, function (item, key) {
    3099       if (item !== undefined) {
    3100         _arr = baseExports.isArray(item)
    3101         if (baseExports.isPlainObject(item) || _arr) {
    3102           params = params.concat(stringifyParams(item, key, _arr))
    3103         } else {
    3104           params.push(encode(key) + '=' + encode(item === null ? '' : item))
    3105         }
    3106       }
    3107     })
    3108     return params.join('&').replace(/%20/g, '+')
    3109   }
    3110 
    3111   var locatExports = {
    3112     parseUrl: parseUrl,
    3113     getBaseURL: getBaseURL,
    3114     locat: locat,
    3115     serialize: serialize,
    3116     unserialize: parseParams
    3117   }
    3118 
    3119   /**
    3120     * 获取一个指定范围内随机数
    3121     *
    3122     * @param {Number} min 最小值
    3123     * @param {Number} max 最大值
    3124     * @return {Number}
    3125     */
    3126   function getRandom (min, max) {
    3127     return min >= max ? min : ((min = min >> 0) + Math.round(Math.random() * ((max || 9) - min)))
    3128   }
    3129 
    3130   function createMinMax (handle) {
    3131     return function (arr, iterate) {
    3132       return handle(XEUtils.sortBy(baseExports.clone(arr), iterate, this))
    3133     }
    3134   }
    3135 
    3136   /**
    3137     * 获取最小值
    3138     *
    3139     * @param {Array} arr 数组
    3140     * @param {Function} iterate(item, index, obj) 回调
    3141     * @return {Number}
    3142     */
    3143   var arrayMin = createMinMax(function (result) {
    3144     return result[0]
    3145   })
    3146 
    3147   /**
    3148     * 获取最大值
    3149     *
    3150     * @param {Array} arr 数组
    3151     * @param {Function} iterate(item, index, obj) 回调
    3152     * @return {Number}
    3153     */
    3154   var arrayMax = createMinMax(function (result) {
    3155     return result.reverse()[0]
    3156   })
    3157 
    3158   /**
    3159     * 千分位分隔符、小数点
    3160     *
    3161     * @param {String/Number} num 数值
    3162     * @param {Object} 参数 {spaceNumber: 分割位数(默认3), separator: 分隔符(默认,), fixed: 小数位数(默认null)}
    3163     * @return {String}
    3164    */
    3165   function commafy (num, options) {
    3166     num = ('' + num).replace(/,/g, '')
    3167     if (num) {
    3168       var opts = baseExports.assign({ spaceNumber: 3, separator: ',' }, options)
    3169       var optFixed = opts.fixed
    3170       var result = (optFixed ? stringToNumber(num).toFixed(optFixed) : num).split('.')
    3171       return result[0].replace(new RegExp('(?=(?!(\b))(\d{' + opts.spaceNumber + '})+$)', 'g'), opts.separator) + (result[1] ? '.' + result[1] : '')
    3172     }
    3173     return num
    3174   }
    3175 
    3176   function createToNumber (handle) {
    3177     return function (str) {
    3178       if (str) {
    3179         var num = handle(str)
    3180         return isNaN(num) ? 0 : num
    3181       }
    3182       return 0
    3183     }
    3184   }
    3185 
    3186   /**
    3187    * 和 Number.toFixed 类似,区别就是不会对小数进行四舍五入,结果返回字符串
    3188    *
    3189    * @param { String/Number } str 数值
    3190    * @return {String}
    3191    */
    3192   function toFixedString (str, digits) {
    3193     var nums = ('' + toFixedNumber(str, digits)).split('.')
    3194     return digits ? [nums[0], '.', XEUtils.padEnd(nums[1] || '', digits, '0')].join('') : nums[0]
    3195   }
    3196 
    3197   /**
    3198    * 和 Number.toFixed 类似,区别就是不会对小数进行四舍五入,结果返回数值
    3199    *
    3200    * @param { String/Number } str 数值
    3201    * @return {String}
    3202    */
    3203   function toFixedNumber (str, digits) {
    3204     if (digits) {
    3205       return stringToNumber(('' + stringToNumber(str)).replace(new RegExp('(\d+.\d{0,' + digits + '}).*'), '$1'))
    3206     }
    3207     return stringToInteger(str)
    3208   }
    3209 
    3210   /**
    3211    * 转数值
    3212    * @param { String/Number } str 数值
    3213    *
    3214    * @return {Number}
    3215    */
    3216   var stringToNumber = createToNumber(parseFloat)
    3217 
    3218   /**
    3219    * 转整数
    3220    * @param { String/Number } str 数值
    3221    *
    3222    * @return {Number}
    3223    */
    3224   var stringToInteger = createToNumber(parseInt)
    3225 
    3226   var numberExports = {
    3227     random: getRandom,
    3228     min: arrayMin,
    3229     max: arrayMax,
    3230     commafy: commafy,
    3231     toFixedString: toFixedString,
    3232     toFixedNumber: toFixedNumber,
    3233     toNumber: stringToNumber,
    3234     toInteger: stringToInteger
    3235   }
    3236 
    3237   /**
    3238     * 去除字符串左右两边的空格
    3239     *
    3240     * @param {String} str 字符串
    3241     * @return {String}
    3242     */
    3243   function stringTrim (str) {
    3244     return str && str.trim ? str.trim() : stringTrimRight(stringTrimLeft(str))
    3245   }
    3246 
    3247   /**
    3248     * 去除字符串左边的空格
    3249     *
    3250     * @param {String} str 字符串
    3251     * @return {String}
    3252     */
    3253   function stringTrimLeft (str) {
    3254     return str && str.trimLeft ? str.trimLeft() : ('' + str).replace(/^[suFEFFxA0]+/g, '')
    3255   }
    3256 
    3257   /**
    3258     * 去除字符串右边的空格
    3259     *
    3260     * @param {String} str 字符串
    3261     * @return {String}
    3262     */
    3263   function stringTrimRight (str) {
    3264     return str && str.trimRight ? str.trimRight() : ('' + str).replace(/[suFEFFxA0]+$/g, '')
    3265   }
    3266 
    3267   var escapeMap = {
    3268     '&': '&amp;',
    3269     '<': '&lt;',
    3270     '>': '&gt;',
    3271     '"': '&quot;',
    3272     "'": '&#x27;',
    3273     '`': '&#x60;'
    3274   }
    3275 
    3276   var unescapeMap = {}
    3277   baseExports.each(escapeMap, function (item, key) {
    3278     unescapeMap[escapeMap[key]] = key
    3279   })
    3280 
    3281   function formatEscaper (dataMap) {
    3282     var replaceRegexp = new RegExp('(?:' + baseExports.keys(dataMap).join('|') + ')', 'g')
    3283     return function (str) {
    3284       return ('' + str).replace(replaceRegexp, function (match) {
    3285         return dataMap[match]
    3286       })
    3287     }
    3288   }
    3289 
    3290   /**
    3291     * 转义HTML字符串,替换&, <, >, ", ', `字符
    3292     *
    3293     * @param {String} str 字符串
    3294     * @return {String}
    3295     */
    3296   var escape = formatEscaper(escapeMap)
    3297 
    3298   /**
    3299     * 反转escape
    3300     *
    3301     * @param {String} str 字符串
    3302     * @return {String}
    3303     */
    3304   var unescape = formatEscaper(unescapeMap)
    3305 
    3306   /**
    3307     * 将带字符串转成驼峰字符串,例如: project-name 转为 projectName
    3308     *
    3309     * @param {String} str 字符串
    3310     * @return {String}
    3311     */
    3312   function camelCase (str) {
    3313     return ('' + str).replace(/(-[a-zA-Z])/g, function (text, u) {
    3314       return u.substring(1).toLocaleUpperCase()
    3315     })
    3316   }
    3317 
    3318   /**
    3319     * 将带驼峰字符串转成字符串,例如: projectName 转为 project-name
    3320     *
    3321     * @param {String} str 字符串
    3322     * @return {String}
    3323     */
    3324   function kebabCase (str) {
    3325     return ('' + str).replace(/([A-Z])/g, function (text, u) {
    3326       return '-' + u.toLowerCase()
    3327     })
    3328   }
    3329 
    3330   /**
    3331     * 将字符串重复 n次
    3332     *
    3333     * @param {String} str 字符串
    3334     * @param {Number} count 次数
    3335     * @return {String}
    3336     */
    3337   function stringRepeat (str, count) {
    3338     var rest = '' + str
    3339     if (str.repeat) {
    3340       return str.repeat(count)
    3341     }
    3342     var list = isNaN(count) ? [] : new Array(parseInt(count))
    3343     return list.join(rest) + (list.length > 0 ? rest : '')
    3344   }
    3345 
    3346   /**
    3347     * 用指定字符从前面开始补全字符串
    3348     *
    3349     * @param {String} str 字符串
    3350     * @param {Number} targetLength 结果长度
    3351     * @param {Number} padString 补全字符
    3352     * @return {String}
    3353     */
    3354   function stringPadStart (str, targetLength, padString, UNDEFINED) {
    3355     var rest = '' + str
    3356     targetLength = targetLength >> 0
    3357     padString = padString === UNDEFINED ? ' ' : '' + padString
    3358     if (rest.padStart) {
    3359       return rest.padStart(targetLength, padString)
    3360     }
    3361     if (targetLength > rest.length) {
    3362       targetLength -= rest.length
    3363       if (targetLength > padString.length) {
    3364         padString += stringRepeat(padString, targetLength / padString.length)
    3365       }
    3366       return padString.slice(0, targetLength) + rest
    3367     }
    3368     return rest
    3369   }
    3370 
    3371   /**
    3372     * 用指定字符从后面开始补全字符串
    3373     *
    3374     * @param {String} str 字符串
    3375     * @param {Number} targetLength 结果长度
    3376     * @param {Number} padString 补全字符
    3377     * @return {String}
    3378     */
    3379   function stringPadEnd (str, targetLength, padString, UNDEFINED) {
    3380     var rest = '' + str
    3381     targetLength = targetLength >> 0
    3382     padString = padString === UNDEFINED ? ' ' : '' + padString
    3383     if (rest.padEnd) {
    3384       return rest.padEnd(targetLength, padString)
    3385     }
    3386     if (targetLength > rest.length) {
    3387       targetLength -= rest.length
    3388       if (targetLength > padString.length) {
    3389         padString += stringRepeat(padString, targetLength / padString.length)
    3390       }
    3391       return rest + padString.slice(0, targetLength)
    3392     }
    3393     return rest
    3394   }
    3395 
    3396   /**
    3397     * 判断字符串是否在源字符串的头部
    3398     *
    3399     * @param {String} str 字符串
    3400     * @param {String/Number} val 值
    3401     * @param {Number} startIndex 开始索引
    3402     * @return {String}
    3403     */
    3404   function stringStartsWith (str, val, startIndex) {
    3405     var rest = '' + str
    3406     return (arguments.length === 1 ? rest : rest.substring(startIndex)).indexOf(val) === 0
    3407   }
    3408 
    3409   /**
    3410     * 判断字符串是否在源字符串的尾部
    3411     *
    3412     * @param {String} str 字符串
    3413     * @param {String/Number} val 值
    3414     * @param {Number} startIndex 开始索引
    3415     * @return {String}
    3416     */
    3417   function stringEndsWith (str, val, startIndex) {
    3418     var rest = '' + str
    3419     return arguments.length === 1 ? rest.indexOf(val) === rest.length - 1 : rest.substring(0, startIndex).indexOf(val) === startIndex - 1
    3420   }
    3421 
    3422   var stringExports = {
    3423     trim: stringTrim,
    3424     trimLeft: stringTrimLeft,
    3425     trimRight: stringTrimRight,
    3426     escape: escape,
    3427     unescape: unescape,
    3428     camelCase: camelCase,
    3429     kebabCase: kebabCase,
    3430     repeat: stringRepeat,
    3431     padStart: stringPadStart,
    3432     padEnd: stringPadEnd,
    3433     startsWith: stringStartsWith,
    3434     endsWith: stringEndsWith
    3435   }
    3436 
    3437   var methodExports = {}
    3438 
    3439   baseExports.assign(
    3440     methodExports,
    3441     arrayExports,
    3442     baseExports,
    3443     browseExports,
    3444     cookieExports,
    3445     dateExports,
    3446     locatExports,
    3447     numberExports,
    3448     stringExports
    3449   )
    3450 
    3451   /**
    3452    * functions of mixing
    3453    *
    3454    * @param {Object} methods
    3455    */
    3456   XEUtils.mixin = function (methods) {
    3457     methodExports.each(methods, function (fn, name) {
    3458       XEUtils[name] = methodExports.isFunction(fn) && fn._c !== false ? function () {
    3459         var result = fn.apply(XEUtils.$context, arguments)
    3460         XEUtils.$context = null
    3461         return result
    3462       } : fn
    3463     })
    3464     return XEUtils
    3465   }
    3466 
    3467   XEUtils.setup = function (options) {
    3468     methodExports.assign(setupDefaults, options)
    3469   }
    3470 
    3471   XEUtils.mixin(methodExports)
    3472 
    3473   return XEUtils
    3474 }))
  • 相关阅读:
    Solr&SpringDataSolr
    Redis简单介绍与使用
    ueditor文本编辑器
    FastDFS
    Vue.js快速入门
    分布式架构Duboo+Zookeeper的基础使用
    Linux基本操作&&Linux操作MySQL
    23种设计模式之代理模式(动态代理)
    23种设计模式之代理模式(静态代理)
    MongoDB入门培训 | 8周入门NoSQL No.1数据库
  • 原文地址:https://www.cnblogs.com/idspring/p/10714079.html
Copyright © 2020-2023  润新知