xhy-xe-utils
Version:
JavaScript 函数库、工具类
2,034 lines (1,870 loc) • 101 kB
JavaScript
/**
* xe-utils.js v2.2.15
* (c) 2017-present Xu Liangzhan
* ISC License.
* @preserve
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory()
: typeof define === 'function' && define.amd ? define(factory)
: (global.XEUtils = factory())
}(this, function () {
'use strict'
var formatString = 'yyyy-MM-dd HH:mm:ss'
var setupDefaults = {
treeOptions: {
parentKey: 'parentId',
key: 'id',
children: 'children'
},
formatDate: formatString + '.SSSZ',
formatString: formatString,
dateDiffRules: [
['yyyy', 31536000000],
['MM', 2592000000],
['dd', 86400000],
['HH', 3600000],
['mm', 60000],
['ss', 1000],
['S', 0]
]
}
function mixin () {
arrayEach(arguments, function (methods) {
each(methods, function (fn, name) {
XEUtils[name] = isFunction(fn) && fn._c !== false ? function () {
var result = fn.apply(XEUtils.$context, arguments)
XEUtils.$context = null
return result
} : fn
})
})
}
function setup (options) {
assign(setupDefaults, options)
}
function XEUtils () { }
XEUtils.v = 'v2'
XEUtils.mixin = mixin
XEUtils.setup = setup
var staticStrUndefined = 'undefined'
var staticStrLast = 'last'
var staticStrFirst = 'first'
var staticDayTime = 86400000
var staticWeekTime = staticDayTime * 7
/* eslint-disable valid-typeof */
var staticLocation = typeof location === staticStrUndefined ? 0 : location
/* eslint-disable valid-typeof */
var staticWindow = typeof window === staticStrUndefined ? 0 : window
/* eslint-disable valid-typeof */
var staticDocument = typeof document === staticStrUndefined ? 0 : document
var staticEncodeURIComponent = encodeURIComponent
var staticDecodeURIComponent = decodeURIComponent
var staticParseInt = parseInt
var staticEscapeMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'`': '`'
}
var staticHGKeyRE = /(.+)?\[(\d+)\]$/
var objectAssignFns = Object.assign
function handleAssign (destination, args, isClone) {
var len = args.length
for (var source, index = 1; index < len; index++) {
source = args[index]
arrayEach(keys(args[index]), isClone ? function (key) {
destination[key] = clone(source[key], isClone)
} : function (key) {
destination[key] = source[key]
})
}
return destination
}
/**
* 浅拷贝一个或者多个对象到目标对象中
*
* @param {Object} obj 目标对象
* @param {...Object}
* @return {Boolean}
*/
var assign = function (target) {
if (target) {
var args = arguments
if (target === true) {
if (args.length > 1) {
target = isArray(target[1]) ? [] : {}
return handleAssign(target, args, true)
}
} else {
return objectAssignFns ? objectAssignFns.apply(Object, args) : handleAssign(target, args)
}
}
return target
}
var extend = assign
/**
* 指定方法后的返回值组成的新对象
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function objectMap (obj, iterate, context) {
var result = {}
if (obj) {
if (iterate) {
if (!isFunction(iterate)) {
iterate = property(iterate)
}
each(obj, function (val, index) {
result[index] = iterate.call(context, val, index, obj)
})
} else {
return obj
}
}
return result
}
function objectEach (obj, iterate, context) {
if (obj) {
for (var key in obj) {
if (hasOwnProp(obj, key)) {
iterate.call(context, obj[key], key, obj)
}
}
}
}
function lastObjectEach (obj, iterate, context) {
lastArrayEach(keys(obj), function (key) {
iterate.call(context, obj[key], key, obj)
})
}
/**
* 数组去重
*
* @param {Array} array 数组
* @return {Array}
*/
function uniq (array) {
var result = []
each(array, function (value) {
if (!includes(result, value)) {
result.push(value)
}
})
return result
}
/**
* 将多个数的值返回唯一的并集数组
*
* @param {...Array} 数组
* @return {Array}
*/
function union () {
var args = arguments
var result = []
var index = 0
var len = args.length
for (; index < len; index++) {
result = result.concat(toArray(args[index]))
}
return uniq(result)
}
// function sortByDef (v1, v2) {
// return v1 > v2 ? 1 : -1
// }
// 支持中文、数字、字母排序 > null > undefined
function sortByDef (v1, v2) {
if (isUndefined(v1)) {
return 1
}
if (isNull(v1)) {
return isUndefined(v2) ? -1 : 1
}
return v1 && v1.localeCompare ? v1.localeCompare(v2) : (v1 > v2 ? 1 : -1)
}
function sortMultis (name, compares) {
return function (item1, item2) {
var v1 = item1[name]
var v2 = item2[name]
if (v1 === v2) {
return compares ? compares(item1, item2) : 0
}
return sortByDef(v1, v2)
}
}
function getSortPros (arr, list, iterate, context) {
iterate = isArray(iterate) ? iterate : [iterate]
arrayEach(iterate, function (prop, index) {
arrayEach(list, isFunction(prop) ? function (val, key) {
val[index] = prop.call(context, val.data, key, arr)
} : function (val) {
val[index] = get(val.data, prop)
})
})
return iterate
}
/**
* 数组按属性值升序
*
* @param {Array} arr 数组
* @param {Function/String/Array} iterate 方法或属性
* @param {Object} context 上下文
* @return {Array}
*/
function sortBy (arr, iterate, context, STR_UNDEFINED) {
if (arr) {
if (iterate === STR_UNDEFINED) {
return toArray(arr).sort(sortByDef)
}
var compares
var list = map(arr, function (item) {
return { data: item }
})
var sortPros = getSortPros(arr, list, iterate, context)
var len = sortPros.length
if (len) {
while (len >= 0) {
compares = sortMultis(len, compares)
len--
}
list = list.sort(compares)
}
return map(list, property('data'))
}
return []
}
/**
* 将一个数组随机打乱,返回一个新的数组
*
* @param {Array} array 数组
* @return {Array}
*/
function shuffle (array) {
var index
var result = []
var list = values(array)
var len = list.length - 1
for (; len >= 0; len--) {
index = len > 0 ? random(0, len) : 0
result.push(list[index])
list.splice(index, 1)
}
return result
}
/**
* 从一个数组中随机返回几个元素
*
* @param {Array} array 数组
* @param {Number} number 个数
* @return {Array}
*/
function sample (array, number) {
var result = shuffle(array)
if (arguments.length <= 1) {
return result[0]
}
if (number < result.length) {
result.length = number || 0
}
return result
}
/**
* 对象中的值中的每一项运行给定函数,如果函数对任一项返回true,则返回true,否则返回false
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Boolean}
*/
var some = helperCreateIterateHandle('some', 1, 0, true, false)
/**
* 对象中的值中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true,否则返回false
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Boolean}
*/
var every = helperCreateIterateHandle('every', 1, 1, false, true)
/**
* 裁剪 Arguments 或数组 array,从 start 位置开始到 end 结束,但不包括 end 本身的位置
* @param {Array/Arguments} array 数组或Arguments
* @param {Number} startIndex 开始索引
* @param {Number} endIndex 结束索引
*/
function slice (array, startIndex, endIndex) {
var result = []
if (array) {
for (startIndex = startIndex || 0, endIndex = endIndex || array.length; startIndex < endIndex; startIndex++) {
result.push(array[startIndex])
}
}
return result
}
/**
* 根据回调过滤数据
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function filter (obj, iterate, context) {
var result = []
if (obj && iterate) {
if (obj.filter) {
return obj.filter(iterate, context)
}
each(obj, function (val, key) {
if (iterate.call(context, val, key, obj)) {
result.push(val)
}
})
}
return result
}
/**
* 查找匹配第一条数据
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
var find = helperCreateIterateHandle('find', 1, 3, true)
/**
* 查找匹配第一条数据的键
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
var findKey = helperCreateIterateHandle('', 0, 2, true)
/**
* 判断对象是否包含该值,成功返回true否则false
*
* @param {Object} obj 对象
* @param {Object} val 值
* @return {Boolean}
*/
function includes (obj, val) {
return indexOf(obj, val) !== -1
}
function arrayIndexOf (obj, val) {
if (obj.indexOf) {
return obj.indexOf(val)
}
for (var index = 0, len = obj.length; index < len; index++) {
if (val === obj[index]) {
return index
}
}
}
function arrayLastIndexOf (obj, val) {
if (obj.lastIndexOf) {
return obj.lastIndexOf(val)
}
for (var len = obj.length - 1; len >= 0; len--) {
if (val === obj[len]) {
return len
}
}
return -1
}
/**
* 指定方法后的返回值组成的新数组
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Array}
*/
function map (obj, iterate, context) {
var result = []
if (obj && arguments.length > 1) {
if (!isFunction(iterate)) {
iterate = property(iterate)
}
if (obj.map) {
return obj.map(iterate, context)
} else {
each(obj, function () {
result.push(iterate.apply(context, arguments))
})
}
}
return result
}
/**
* 求和函数,将数值相加
*
* @param {Array} array 数组
* @param {Function/String} iterate 方法或属性
* @param {Object} context 上下文
* @return {Number}
*/
function sum (array, iterate, context) {
var result = 0
each(array, iterate ? isFunction(iterate) ? function () {
result += toNumber(iterate.apply(context, arguments))
} : function (val) {
result += toNumber(val[iterate])
} : function (val) {
result += toNumber(val)
})
return result
}
/**
* 求平均值函数
*
* @param {Array} array 数组
* @param {Function/String} iterate 方法或属性
* @param {Object} context 上下文
* @return {Number}
*/
function mean (array, iterate, context) {
return toNumber(sum(array, iterate, context) / getSize(array))
}
/**
* 接收一个函数作为累加器,数组中的每个值(从左到右)开始合并,最终为一个值。
*
* @param {Array} array 数组
* @param {Function} callback 方法
* @param {Object} initialValue 初始值
* @return {Number}
*/
function reduce (array, callback, initialValue) {
if (array) {
var len, reduceMethod
var index = 0
var context = null
var previous = initialValue
var isInitialVal = arguments.length > 2
var keyList = keys(array)
if (array.length && array.reduce) {
reduceMethod = function () {
return callback.apply(context, arguments)
}
if (isInitialVal) {
return array.reduce(reduceMethod, previous)
}
return array.reduce(reduceMethod)
}
if (isInitialVal) {
index = 1
previous = array[keyList[0]]
}
for (len = keyList.length; index < len; index++) {
previous = callback.call(context, previous, array[keyList[index]], index, array)
}
return previous
}
}
/**
* 浅复制数组的一部分到同一数组中的另一个位置,数组大小不变
*
* @param {Array} array 数组
* @param {Number} target 从该位置开始替换数据
* @param {Number} start 从该位置开始读取数据,默认为 0 。如果为负值,表示倒数
* @param {Number} end 到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数
* @return {Array}
*/
function copyWithin (array, target, start, end) {
if (isArray(array) && array.copyWithin) {
return array.copyWithin(target, start, end)
}
var replaceIndex, replaceArray
var targetIndex = target >> 0
var startIndex = start >> 0
var len = array.length
var endIndex = arguments.length > 3 ? end >> 0 : len
if (targetIndex < len) {
targetIndex = targetIndex >= 0 ? targetIndex : len + targetIndex
if (targetIndex >= 0) {
startIndex = startIndex >= 0 ? startIndex : len + startIndex
endIndex = endIndex >= 0 ? endIndex : len + endIndex
if (startIndex < endIndex) {
for (replaceIndex = 0, replaceArray = array.slice(startIndex, endIndex); targetIndex < len; targetIndex++) {
if (replaceArray.length <= replaceIndex) {
break
}
array[targetIndex] = replaceArray[replaceIndex++]
}
}
}
}
return array
}
/**
* 将一个数组分割成大小的组。如果数组不能被平均分配,那么最后一块将是剩下的元素
*
* @param {Array} array 数组
* @param {Number} size 每组大小
* @return {Array}
*/
function chunk (array, size) {
var index
var result = []
var arrLen = size >> 0 || 1
if (isArray(array)) {
if (arrLen >= 0 && array.length > arrLen) {
index = 0
while (index < array.length) {
result.push(array.slice(index, index + arrLen))
index += arrLen
}
} else {
result = array.length ? [array] : array
}
}
return result
}
/**
* 将每个数组中相应位置的值合并在一起
*
* @param {Array*} array 数组
*/
function zip () {
return unzip(arguments)
}
/**
* 与 zip 相反
*
* @param {Array} arrays 数组集合
*/
function unzip (arrays) {
var index, maxItem, len
var result = []
if (arrays && arrays.length) {
index = 0
maxItem = max(arrays, function (item) {
return item ? item.length : 0
})
for (len = maxItem ? maxItem.length : 0; index < len; index++) {
result.push(map(arrays, index))
}
}
return result
}
/**
* 根据键数组、值数组对转换为对象
*
* @param {Array} props 键数组
* @param {Number} arr 值数组
* @return {Object}
*/
function zipObject (props, arr) {
var result = {}
arr = arr || []
each(values(props), function (val, key) {
result[val] = arr[key]
})
return result
}
/**
* 将对象或者伪数组转为新数组
*
* @param {Array} obj 数组
* @return {Array}
*/
function toArray (array) {
return map(array, function (item) {
return item
})
}
/**
* 判断数组是否包含另一数组
*
* @param {Array} array1 数组
* @param {Array} array2 被包含数组
* @return {Boolean}
*/
function includeArrays (array1, array2) {
var len
var index = 0
if (isArray(array1) && isArray(array2)) {
for (len = array2.length; index < len; index++) {
if (!includes(array1, array2[index])) {
return false
}
}
return true
}
return includes(array1, array2)
}
/**
* 获取数组对象中某属性值,返回一个数组
*
* @param {Array} array 数组
* @param {String} key 属性值
* @return {Array}
*/
function pluck (obj, key) {
return map(obj, key)
}
function deepGetObj (obj, path) {
var index = 0
var len = path.length
while (obj && index < len) {
obj = obj[path[index++]]
}
return len && obj ? obj : 0
}
/**
* 在list的每个元素上执行方法,任何传递的额外参数都会在调用方法的时候传递给它
*
* @param {Array} list
* @param {Array/String/Function} path
* @param {...Object} arguments
* @return {Array}
*/
function invoke (list, path) {
var func
var args = arguments
var params = []
var paths = []
var index = 2
var len = args.length
for (; index < len; index++) {
params.push(args[index])
}
if (isArray(path)) {
len = path.length - 1
for (index = 0; index < len; index++) {
paths.push(path[index])
}
path = path[len]
}
return map(list, function (context) {
if (paths.length) {
context = deepGetObj(context, paths)
}
func = context[path] || path
if (func && func.apply) {
return func.apply(context, params)
}
})
}
var invokeMap = invoke
function arrayEach (obj, iterate, context) {
if (obj) {
if (obj.forEach) {
obj.forEach(iterate, context)
} else {
for (var index = 0, len = obj.length; index < len; index++) {
iterate.call(context, obj[index], index, obj)
}
}
}
}
function lastArrayEach (obj, iterate, context) {
for (var len = obj.length - 1; len >= 0; len--) {
iterate.call(context, obj[len], len, obj)
}
}
function strictTree (array, optChildren) {
each(array, function (item) {
if (item.children && !item.children.length) {
remove(item, optChildren)
}
})
}
/**
* 将一个带层级的数据列表转成树结构
*
* @param {Array} array 数组
* @param {Object} options {strict: false, parentKey: 'parentId', key: 'id', children: 'children', data: 'data'}
* @return {Array}
*/
function toArrayTree (array, options) {
var opts = assign({}, setupDefaults.treeOptions, options)
var optStrict = opts.strict
var optKey = opts.key
var optParentKey = opts.parentKey
var optChildren = opts.children
var optSortKey = opts.sortKey
var optReverse = opts.reverse
var optData = opts.data
var result = []
var treeMap = {}
var idList, id, treeData, parentId
if (optSortKey) {
array = sortBy(clone(array), optSortKey)
if (optReverse) {
array = array.reverse()
}
}
idList = map(array, function (item) {
return item[optKey]
})
each(array, function (item) {
id = item[optKey]
if (optData) {
treeData = {}
treeData[optData] = item
} else {
treeData = item
}
parentId = item[optParentKey]
treeMap[id] = treeMap[id] || []
treeMap[parentId] = treeMap[parentId] || []
treeMap[parentId].push(treeData)
treeData[optKey] = id
treeData[optParentKey] = parentId
treeData[optChildren] = treeMap[id]
if (!optStrict || (optStrict && !parentId)) {
if (!includes(idList, parentId)) {
result.push(treeData)
}
}
})
if (optStrict) {
strictTree(array, optChildren)
}
return result
}
function unTreeList (result, array, opts) {
var children
var optChildren = opts.children
var optData = opts.data
each(array, function (item) {
children = item[optChildren]
if (optData) {
item = item[optData]
}
result.push(item)
if (children) {
unTreeList(result, children, opts)
}
})
return result
}
/**
* 将一个树结构转成数组列表
*
* @param {Array} array 数组
* @param {Object} options {children: 'children', data: 'data'}
* @return {Array}
*/
function toTreeArray (array, options) {
return unTreeList([], array, assign({}, setupDefaults.treeOptions, options))
}
function findTreeItem (parent, obj, iterate, context, path, node, parseChildren, opts) {
if (obj) {
var item, index, len, paths, nodes, match
for (index = 0, len = obj.length; index < len; index++) {
item = obj[index]
paths = path.concat(['' + index])
nodes = node.concat([item])
if (iterate.call(context, item, index, obj, paths, parent, nodes)) {
return { index: index, item: item, path: paths, items: obj, parent: parent, nodes: nodes }
}
if (parseChildren && item) {
match = findTreeItem(item, item[parseChildren], iterate, context, paths.concat([parseChildren]), nodes, parseChildren, opts)
if (match) {
return match
}
}
}
}
}
/**
* 从树结构中查找匹配第一条数据的键、值、路径
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, items, path, parent, nodes) 回调
* @param {Object} options {children: 'children'}
* @param {Object} context 上下文
* @return {Object} { item, index, items, path, parent, nodes }
*/
var findTree = helperCreateTreeFunc(findTreeItem)
function eachTreeItem (parent, obj, iterate, context, path, node, parseChildren, opts) {
var paths, nodes
each(obj, function (item, index) {
paths = path.concat(['' + index])
nodes = node.concat([item])
iterate.call(context, item, index, obj, paths, parent, nodes)
if (item && parseChildren) {
paths.push(parseChildren)
eachTreeItem(item, item[parseChildren], iterate, context, paths, nodes, parseChildren, opts)
}
})
}
/**
* 从树结构中遍历数据的键、值、路径
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, items, path, parent, nodes) 回调
* @param {Object} options {children: 'children', mapChildren: 'children}
* @param {Object} context 上下文
*/
var eachTree = helperCreateTreeFunc(eachTreeItem)
function mapTreeItem (parent, obj, iterate, context, path, node, parseChildren, opts) {
var paths, nodes, rest
var mapChildren = opts.mapChildren || parseChildren
return map(obj, function (item, index) {
paths = path.concat(['' + index])
nodes = node.concat([item])
rest = iterate.call(context, item, index, obj, paths, parent, nodes)
if (rest && item && parseChildren && item[parseChildren]) {
rest[mapChildren] = mapTreeItem(item, item[parseChildren], iterate, context, paths, nodes, parseChildren, opts)
}
return rest
})
}
/**
* 从树结构中指定方法后的返回值组成的新数组
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, items, path, parent, nodes) 回调
* @param {Object} options {children: 'children'}
* @param {Object} context 上下文
* @return {Object/Array}
*/
var mapTree = helperCreateTreeFunc(mapTreeItem)
/**
* 从树结构中根据回调过滤数据
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, items, path, parent) 回调
* @param {Object} options {children: 'children'}
* @param {Object} context 上下文
* @return {Array}
*/
function filterTree (obj, iterate, options, context) {
var result = []
if (obj && iterate) {
eachTree(obj, function (item, index, items, path, parent, nodes) {
if (iterate.call(context, item, index, items, path, parent, nodes)) {
result.push(item)
}
}, options)
}
return result
}
function searchTreeItem (parentAllow, parent, obj, iterate, context, path, node, parseChildren, opts) {
var paths, nodes, rest, isAllow, hasChild
var rests = []
var hasOriginal = opts.original
var mapChildren = opts.mapChildren || parseChildren
arrayEach(obj, function (item, index) {
paths = path.concat(['' + index])
nodes = node.concat([item])
isAllow = parentAllow || iterate.call(context, item, index, obj, paths, parent, nodes)
hasChild = parseChildren && item[parseChildren]
if (isAllow || hasChild) {
rest = hasOriginal ? item : assign({}, item)
}
if (isAllow || hasChild) {
rest[mapChildren] = searchTreeItem(isAllow, item, item[parseChildren], iterate, context, paths, nodes, parseChildren, opts)
if (isAllow || rest[mapChildren].length) {
rests.push(rest)
}
} else if (isAllow) {
rests.push(rest)
}
})
return rests
}
/**
* 从树结构中根据回调查找数据
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, items, path, parent, nodes) 回调
* @param {Object} options {children: 'children'}
* @param {Object} context 上下文
* @return {Array}
*/
var searchTree = helperCreateTreeFunc(function (parent, obj, iterate, context, path, nodes, parseChildren, opts) {
return searchTreeItem(0, parent, obj, iterate, context, path, nodes, parseChildren, opts)
})
function helperCreateIterateHandle (prop, useArray, restIndex, matchValue, defaultValue) {
return function (obj, iterate, context) {
if (obj && iterate) {
if (prop && obj[prop]) {
return obj[prop](iterate, context)
} else {
if (useArray && isArray(obj)) {
for (var index = 0, len = obj.length; index < len; index++) {
if (!!iterate.call(context, obj[index], index, obj) === matchValue) {
return [true, false, index, obj[index]][restIndex]
}
}
} else {
for (var key in obj) {
if (hasOwnProp(obj, key)) {
if (!!iterate.call(context, obj[key], key, obj) === matchValue) {
return [true, false, key, obj[key]][restIndex]
}
}
}
}
}
}
return defaultValue
}
}
function helperCreateTreeFunc (handle) {
return function (obj, iterate, options, context) {
var opts = options || {}
var optChildren = opts.children || 'children'
return handle(null, obj, iterate, context, [], [], optChildren, opts)
}
}
/**
* 判断对象自身属性中是否具有指定的属性
*
* @param {Object} obj 对象
* @param {String/Number} key 键值
* @return {Boolean}
*/
function hasOwnProp (obj, key) {
return obj.hasOwnProperty(key)
}
/**
* 判断是否 undefined 和 null
* @param {Object} obj 对象
* @return {Boolean}
*/
function eqNull (obj) {
return isNull(obj) || isUndefined(obj)
}
/* eslint-disable eqeqeq */
function isNumberNaN (obj) {
return isNumber(obj) && isNaN(obj)
}
function isNumberFinite (obj) {
return isNumber(obj) && isFinite(obj)
}
/**
* 判断是否Undefined
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isUndefined = helperCreateInTypeof(staticStrUndefined)
/**
* 判断是否数组
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isArray = Array.isArray || helperCreateInInObjectString('Array')
/**
* 判断是否小数
*
* @param {Number} obj 数值
* @return {Boolean}
*/
function isFloat (obj) {
return !isNull(obj) && !isNaN(obj) && !isArray(obj) && !isInteger(obj)
}
/**
* 判断是否整数
*
* @param {Number, String} number 数值
* @return {Boolean}
*/
var isInteger = function (obj) {
return !isNull(obj) && !isNaN(obj) && !isArray(obj) && obj % 1 === 0
}
/**
* 判断是否方法
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isFunction = helperCreateInTypeof('function')
/**
* 判断是否Boolean对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isBoolean = helperCreateInTypeof('boolean')
/**
* 判断是否String对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isString = helperCreateInTypeof('string')
/**
* 判断是否Number对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isNumber = helperCreateInTypeof('number')
/**
* 判断是否RegExp对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isRegExp = helperCreateInInObjectString('RegExp')
/**
* 判断是否Object对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isObject = helperCreateInTypeof('object')
/**
* 判断是否对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isPlainObject (obj) {
return obj ? obj.constructor === Object : false
}
/**
* 判断是否Date对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isDate = helperCreateInInObjectString('Date')
/**
* 判断是否Error对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isError = helperCreateInInObjectString('Error')
/**
* 判断是否TypeError对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isTypeError (obj) {
return obj ? obj.constructor === TypeError : false
}
/**
* 判断是否为空对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isEmpty (obj) {
for (var key in obj) {
return false
}
return true
}
/**
* 判断是否为Null
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isNull (obj) {
return obj === null
}
/* eslint-disable valid-typeof */
/**
* 判断是否Symbol对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportSymbol = typeof Symbol !== staticStrUndefined
function isSymbol (obj) {
return supportSymbol && Symbol.isSymbol ? Symbol.isSymbol(obj) : (typeof obj === 'symbol')
}
/**
* 判断是否Arguments对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var isArguments = helperCreateInInObjectString('Arguments')
/**
* 判断是否Element对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isElement (obj) {
return !!(obj && isString(obj.nodeName) && isNumber(obj.nodeType))
}
/**
* 判断是否Document对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isDocument (obj) {
return !!(obj && staticDocument && obj.nodeType === 9)
}
/**
* 判断是否Window对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
function isWindow (obj) {
return staticWindow && !!(obj && obj === obj.window)
}
/* eslint-disable valid-typeof */
/**
* 判断是否FormData对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportFormData = typeof FormData !== staticStrUndefined
function isFormData (obj) {
return supportFormData && obj instanceof FormData
}
/* eslint-disable valid-typeof */
/**
* 判断是否Map对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportMap = typeof Map !== staticStrUndefined
function isMap (obj) {
return supportMap && obj instanceof Map
}
/* eslint-disable valid-typeof */
/**
* 判断是否WeakMap对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportWeakMap = typeof WeakMap !== staticStrUndefined
function isWeakMap (obj) {
return supportWeakMap && obj instanceof WeakMap
}
/* eslint-disable valid-typeof */
/**
* 判断是否Set对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportSet = typeof Set !== staticStrUndefined
function isSet (obj) {
return supportSet && obj instanceof Set
}
/* eslint-disable valid-typeof */
/**
* 判断是否WeakSet对象
*
* @param {Object} obj 对象
* @return {Boolean}
*/
var supportWeakSet = typeof WeakSet !== staticStrUndefined
function isWeakSet (obj) {
return supportWeakSet && obj instanceof WeakSet
}
/**
* 判断是否闰年
*
* @param {Date} date 日期或数字
* @return {Boolean}
*/
function isLeapYear (date) {
var year
var currentDate = date ? toStringDate(date) : helperNewDate()
if (isDate(currentDate)) {
year = currentDate.getFullYear()
return (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0)
}
return false
}
/**
* 判断属性中的键和值是否包含在对象中
*
* @param {Object/Array} obj 对象
* @param {Object} source 值
* @return {Boolean}
*/
function isMatch (obj, source) {
var objKeys = keys(obj)
var sourceKeys = keys(source)
if (sourceKeys.length) {
if (includeArrays(objKeys, sourceKeys)) {
return some(sourceKeys, function (key2) {
return findIndexOf(objKeys, function (key1) {
return key1 === key2 && isEqual(obj[key1], source[key2])
}) > -1
})
}
} else {
return true
}
return isEqual(obj, source)
}
/**
* 深度比较两个对象之间的值是否相等
*
* @param {Object} obj1 值1
* @param {Object} obj2 值2
* @return {Boolean}
*/
function isEqual (obj1, obj2) {
return helperEqualCompare(obj1, obj2, helperDefaultCompare)
}
/**
* 深度比较两个对象之间的值是否相等,使用自定义比较函数
*
* @param {Object} obj1 值1
* @param {Object} obj2 值2
* @param {Function} func 自定义函数
* @return {Boolean}
*/
function isEqualWith (obj1, obj2, func) {
if (isFunction(func)) {
return helperEqualCompare(obj1, obj2, function (v1, v2, key, obj1, obj2) {
var result = func(v1, v2, key, obj1, obj2)
return isUndefined(result) ? helperDefaultCompare(v1, v2) : !!result
}, func)
}
return helperEqualCompare(obj1, obj2, helperDefaultCompare)
}
/**
* 获取对象类型
*
* @param {Object} obj 对象
* @return {String}
*/
function getType (obj) {
if (isNull(obj)) {
return 'null'
}
if (isSymbol(obj)) {
return 'symbol'
}
if (isDate(obj)) {
return 'date'
}
if (isArray(obj)) {
return 'array'
}
if (isRegExp(obj)) {
return 'regexp'
}
if (isError(obj)) {
return 'error'
}
return typeof obj
}
/**
* 获取一个全局唯一标识
*
* @param {String} prefix 前缀
* @return {Number}
*/
var __uniqueId = 0
function uniqueId (prefix) {
return (prefix ? '' + prefix : 0) + ++__uniqueId
}
/**
* 返回对象的长度
*
* @param {Object} obj 对象
* @return {Number}
*/
function getSize (obj) {
var len = 0
if (isString(obj) || isArray(obj)) {
return obj.length
}
each(obj, function () {
len++
})
return len
}
/**
* 返回对象第一个索引值
*
* @param {Object} obj 对象
* @param {Object} val 值
* @return {Number}
*/
var indexOf = helperCreateIndexOf('indexOf', arrayIndexOf)
/**
* 从最后开始的索引值,返回对象第一个索引值
*
* @param {Object} array 对象
* @param {Object} val 值
* @return {Number}
*/
var lastIndexOf = helperCreateIndexOf('lastIndexOf', arrayLastIndexOf)
/**
* 返回对象第一个索引值
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
var findIndexOf = helperCreateiterateIndexOf(function (obj, iterate, context) {
for (var index = 0, len = obj.length; index < len; index++) {
if (iterate.call(context, obj[index], index, obj)) {
return index
}
}
return -1
})
/**
* 从最后开始的索引值,返回对象第一个索引值
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
var findLastIndexOf = helperCreateiterateIndexOf(function (obj, iterate, context) {
for (var len = obj.length - 1; len >= 0; len--) {
if (iterate.call(context, obj[len], len, obj)) {
return len
}
}
return -1
})
/**
* 字符串转JSON
*
* @param {String} str 字符串
* @return {Object} 返回转换后对象
*/
function toStringJSON (str) {
if (isObject(str)) {
return str
} else if (isString(str)) {
try {
return JSON.parse(str)
} catch (e) { }
}
return {}
}
/**
* JSON转字符串
*
* @param {Object} obj 对象
* @return {String} 返回字符串
*/
function toJSONString (obj) {
return JSON.stringify(obj) || ''
}
/**
* 获取对象所有属性
*
* @param {Object} obj 对象/数组
* @return {Array}
*/
var keys = helperCreateGetObjects('keys', 1)
/**
* 获取对象所有值
*
* @param {Object} obj 对象/数组
* @return {Array}
*/
var values = helperCreateGetObjects('values', 0)
/**
* 获取对象所有属性、值
*
* @param {Object} obj 对象/数组
* @return {Array}
*/
var entries = helperCreateGetObjects('entries', 2)
/**
* 根据 key 过滤指定的属性值,返回一个新的对象
*
* @param {Object} obj 对象
* @param {String/Array} key 键数组
* @return {Object}
*/
var pick = helperCreatePickOmit(1, 0)
/**
* 根据 key 排除指定的属性值,返回一个新的对象
*
* @param {Object} obj 对象
* @param {String/Array} key 键数组
* @return {Object}
*/
var omit = helperCreatePickOmit(0, 1)
/**
* 获取对象第一个值
*
* @param {Object} obj 对象/数组
* @return {Object}
*/
function first (obj) {
return values(obj)[0]
}
/**
* 获取对象最后一个值
*
* @param {Object} obj 对象/数组
* @return {Object}
*/
function last (obj) {
var list = values(obj)
return list[list.length - 1]
}
/**
* 迭代器
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function each (obj, iterate, context) {
if (obj) {
return (isArray(obj) ? arrayEach : objectEach)(obj, iterate, context)
}
return obj
}
/**
* 迭代器,支持 return false 跳出循环 break
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function forOf (obj, iterate, context) {
if (obj) {
if (isArray(obj)) {
for (var index = 0, len = obj.length; index < len; index++) {
if (iterate.call(context, obj[index], index, obj) === false) {
break
}
}
} else {
for (var key in obj) {
if (hasOwnProp(obj, key)) {
if (iterate.call(context, obj[key], key, obj) === false) {
break
}
}
}
}
}
}
/**
* 迭代器,从最后开始迭代,支持 return false 跳出循环 break
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function lastForOf (obj, iterate, context) {
if (obj) {
var len, list
if (isArray(obj)) {
for (len = obj.length - 1; len >= 0; len--) {
if (iterate.call(context, obj[len], len, obj) === false) {
break
}
}
} else {
list = keys(obj)
for (len = list.length - 1; len >= 0; len--) {
if (iterate.call(context, obj[list[len]], list[len], obj) === false) {
break
}
}
}
}
}
/**
* 迭代器,从最后开始迭代
*
* @param {Object} obj 对象/数组
* @param {Function} iterate(item, index, obj) 回调
* @param {Object} context 上下文
* @return {Object}
*/
function lastEach (obj, iterate, context) {
if (obj) {
return (isArray(obj) ? lastArrayEach : lastObjectEach)(obj, iterate, context)
}
return obj
}
/**
* 检查键、路径是否是该对象的属性
*
* @param {Object/Array} data 对象
* @param {String/Function} property 键、路径
* @return {Boolean}
*/
function has (obj, property) {
if (obj) {
if (hasOwnProp(obj, property)) {
return true
} else {
var prop, arrIndex, objProp, matchs, rest, isHas
var props = helperGetHGSKeys(property)
var index = 0
var len = props.length
for (rest = obj; index < len; index++) {
isHas = false
prop = props[index]
matchs = prop ? prop.match(staticHGKeyRE) : ''
if (matchs) {
arrIndex = matchs[1]
objProp = matchs[2]
if (arrIndex) {
if (rest[arrIndex]) {
if (hasOwnProp(rest[arrIndex], objProp)) {
isHas = true
rest = rest[arrIndex][objProp]
}
}
} else {
if (hasOwnProp(rest, objProp)) {
isHas = true
rest = rest[objProp]
}
}
} else {
if (hasOwnProp(rest, prop)) {
isHas = true
rest = rest[prop]
}
}
if (isHas) {
if (index === len - 1) {
return true
}
} else {
break
}
}
}
}
return false
}
/**
* 获取对象的属性的值,如果值为 undefined,则返回默认值
* @param {Object/Array} obj 对象
* @param {String/Function} property 键、路径
* @param {Object} defaultValue 默认值
* @return {Object}
*/
function get (obj, property, defaultValue) {
if (eqNull(obj)) {
return defaultValue
}
var result = pathGet(obj, property)
return isUndefined(result) ? defaultValue : result
}
function valGet (obj, key) {
var matchs = key ? key.match(staticHGKeyRE) : ''
return matchs ? (matchs[1] ? (obj[matchs[1]] ? obj[matchs[1]][matchs[2]] : undefined) : obj[matchs[2]]) : obj[key]
}
function pathGet (obj, property) {
if (obj) {
var rest, props, len
var index = 0
if (obj[property] || hasOwnProp(obj, property)) {
return obj[property]
} else {
props = helperGetHGSKeys(property)
len = props.length
if (len) {
for (rest = obj; index < len; index++) {
rest = valGet(rest, props[index])
if (eqNull(rest)) {
return
}
}
}
return rest
}
}
}
var sKeyRE = /(.+)\[(\d+)\]$/
function valSet (obj, key, isSet, value) {
if (obj[key]) {
if (isSet) {
obj[key] = value
}
} else {
var index
var matchs = key ? key.match(sKeyRE) : null
var rest = isSet ? value : {}
if (matchs) {
index = staticParseInt(matchs[2])
if (obj[matchs[1]]) {
obj[matchs[1]][index] = rest
} else {
obj[matchs[1]] = new Array(index + 1)
obj[matchs[1]][index] = rest
}
} else {
obj[key] = rest
}
return rest
}
return obj[key]
}
/**
* 设置对象属性上的值。如果属性不存在则创建它
* @param {Object/Array} obj 对象
* @param {String/Function} property 键、路径
* @param {Object} value 值
*/
function set (obj, property, value) {
if (obj) {
if (obj[property] || hasOwnProp(obj, property)) {
obj[property] = value
} else {
var rest = obj
var props = helperGetHGSKeys(property)
var len = props.length
for (var index = 0; index < len; index++) {
rest = valSet(rest, props[index], index === len - 1, value)
}
}
}
return obj
}
function createiterateEmpty (iterate) {
return function () {
return isEmpty(iterate)
}
}
/**
* 集合分组,默认使用键值分组,如果有iterate则使用结果进行分组
*
* @param {Array} obj 对象
* @param {Function} iterate 回调/对象属性
* @param {Object} context 上下文
* @return {Object}
*/
function groupBy (obj, iterate, context) {
var groupKey
var result = {}
if (obj) {
if (iterate && isObject(iterate)) {
iterate = createiterateEmpty(iterate)
} else if (!isFunction(iterate)) {
iterate = property(iterate)
}
each(obj, function (val, key) {
groupKey = iterate ? iterate.call(context, val, key, obj) : val
if (result[groupKey]) {
result[groupKey].push(val)
} else {
result[groupKey] = [val]
}
})
}
return result
}
/**
* 集合分组统计,返回各组中对象的数量统计
*
* @param {Array} obj 对象
* @param {Function} iterate 回调/对象属性
* @param {Object} context 上下文
* @return {Object}
*/
function countBy (obj, iterate, context) {
var result = groupBy(obj, iterate, context || this)
objectEach(result, function (item, key) {
result[key] = item.length
})
return result
}
function startClone (func, obj, deep) {
return func(obj, deep ? function (val) {
return deepClone(val, deep)
} : function (val) {
return val
})
}
function deepClone (val, deep) {
return isPlainObject(val) ? startClone(objectMap, val, deep) : isArray(val) ? startClone(map, val, deep) : val
}
/**
* 浅拷贝/深拷贝
*
* @param {Object} obj 对象/数组
* @param {Boolean} deep 是否深拷贝
* @return {Object}
*/
function clone (obj, deep) {
if (obj) {
return deepClone(obj, deep)
}
return obj
}
/**
* 清空对象
*
* @param {Object} obj 对象
* @param {*} defs 默认值,如果不传(清空所有属性)、如果传对象(清空并继承)、如果传值(给所有赋值)
* @param {Object/Array} assigns 默认值
* @return {Object}
*/
function clear (obj, defs, assigns) {
if (obj) {
var len
var isDefs = arguments.length > 1 && (isNull(defs) || !isObject(defs))
var extds = isDefs ? assigns : defs
if (isPlainObject(obj)) {
objectEach(obj, isDefs ? function (val, key) {
obj[key] = defs
} : function (val, key) {
helperDeleteProperty(obj, key)
})
if (extds) {
assign(obj, extds)
}
} else if (isArray(obj)) {
if (isDefs) {
len = obj.length
while (len > 0) {
len--
obj[len] = defs
}
} else {
obj.length = 0
}
if (extds) {
obj.push.apply(obj, extds)
}
}
}
return obj
}
function pluckProperty (name) {
return function (obj, key) {
return key === name
}
}
/**
* 移除对象属性
*
* @param {Object/Array} obj 对象/数组
* @param {Function/String} iterate 方法或属性
* @param {Object} context 上下文
* @return {Object/Array}
*/
function remove (obj, iterate, context) {
if (obj) {
if (!eqNull(iterate)) {
var removeKeys = []
var rest = []
if (!isFunction(iterate)) {
iterate = pluckProperty(iterate)
}
each(obj, function (item, index, rest) {
if (iterate.call(context, item, index, rest)) {
removeKeys.push(index)
}
})
if (isArray(obj)) {
lastEach(removeKeys, function (item, key) {
rest.push(obj[item])
obj.splice(item, 1)
})
} else {
rest = {}
arrayEach(removeKeys, function (key) {
rest[key] = obj[key]
helperDeleteProperty(obj, key)
})
}
return rest
}
return clear(obj)
}
return obj
}
/**
* 序号列表生成函数
*
* @param {Number} start 起始值
* @param {Number} stop 结束值
* @param {Number} step 自增值
* @return {Object}
*/
function range (start, stop, step) {
var index, len
var result = []
var args = arguments
if (args.length < 2) {
stop = args[0]
start = 0
}
index = start >> 0
len = stop >> 0
if (index < stop) {
step = step >> 0 || 1
for (; index < len; index += step) {
result.push(index)
}
}
return result
}
/**
* 将一个或者多个对象值解构到目标对象
*
* @param {Object} destination 目标对象
* @param {...Object}
* @return {Boolean}
*/
function destructuring (destination, sources) {
if (destination && sources) {
var rest = assign.apply(this, [{}].concat(slice(arguments, 1)))
var restKeys = keys(rest)
arrayEach(keys(destination), function (key) {
if (includes(restKeys, key)) {
destination[key] = rest[key]
}
})
}
return destination
}
function helperCreateGetObjects (name, getIndex) {
var proMethod = Object[name]
return function (obj) {
var result = []
if (obj) {
if (proMethod) {
return proMethod(obj)
}
each(obj, getIndex > 1 ? function (key) {
result.push(['' + key, obj[key]])
} : function () {
result.push(arguments[getIndex])
})
}
return result
}
}
function helperCreateIndexOf (name, callback) {
return function (obj, val) {
if (obj) {
if (typeof obj === 'string' || isArray(obj)) {
if (obj[name]) {
return obj[name](val)
}
return callback(obj, val)
}
for (var key in obj) {
if (hasOwnProp(obj, key)) {
if (val === obj[key]) {
return key
}
}