UNPKG

xhy-xe-utils

Version:
2,034 lines (1,870 loc) 101 kB
/** * 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 = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#x27;', '`': '&#x60;' } 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 } }