UNPKG

mix-ui

Version:

mix-ui,对于uView UI的补充和组合,用于uni-app生态的UI框架

238 lines (213 loc) 7.37 kB
//#region defaultIsMergeableObject function isNonNullObject(value) { return !!value && typeof value === 'object' } function getType(o) { return Object.prototype.toString.call(o) } function isSpecial(value) { var stringValue = getType(value) return stringValue === '[object RegExp]' || stringValue === '[object Date]' || isReactElement(value) } // see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 var canUseSymbol = typeof Symbol === 'function' && Symbol.for var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7 function isReactElement(value) { return value.$$typeof === REACT_ELEMENT_TYPE } function defaultIsMergeableObject(value) { return isNonNullObject(value) && !isSpecial(value) } //#endregion function emptyTarget(val) { return Array.isArray(val) ? [] : {} } function copyFn(fn) { var result = new Function('return ' + fn)() for (var i in fn) { result[i] = fn[i] } return result } function copySymbol(val) { var str = val.toString() var tempArr = str.split('(') var arr = tempArr[1].split(')')[0] return Symbol(arr) } function copyRegExp(re) { function getRegExpFlags(re) { var flags = '' if (re.global) flags += 'g' if (re.ignoreCase) flags += 'i' if (re.multiline) flags += 'm' return flags } return new RegExp(re.source, getRegExpFlags(re)) } function copyDate(date) { return new Date(date.getTime()) } // 除非是特殊对象(isMergeableObject),否则克隆(克隆到空对象或空数组中去) function cloneUnlessOtherwiseSpecified(value, options) { if (options.clone !== false && options.isMergeableObject(value)) { return clone(emptyTarget(value), value, options) } else { var stringValue = getType(value) if (stringValue === '[object RegExp]') { return copyRegExp(value) } else if (stringValue === '[object Date]') { return copyDate(value) } else if (stringValue === '[object Function]') { return copyFn(value) } else if (stringValue === '[object Symbol]') { return copySymbol(value) } else { return value } } } // 默认的数组合并 function defaultArrayMerge(target, source, options) { return target.concat(source).map(function(element) { return cloneUnlessOtherwiseSpecified(element, options) }) } // 合并两个数组中同一索引的对象。 function indexArrayMerge(target, source, options) { const destination = target.slice() source.forEach((item, index) => { // if (typeof destination[index] === 'undefined') { // destination[index] = options.cloneUnlessOtherwiseSpecified(item, options) // } else if (options.isMergeableObject(item)) { // destination[index] = clone(target[index], item, options) // } else if (target.indexOf(item) === -1) { // destination.push(item) // } if (options.isMergeableObject(item)) { destination[index] = clone(target[index], item, options) } else if (target.indexOf(item) === -1) { destination[index] = options.cloneUnlessOtherwiseSpecified(item, options) } }) return destination } // 获取合并function function getMergeFunction(key, options) { if (!options.customMerge) { return clone } var customMerge = options.customMerge(key) return typeof customMerge === 'function' ? customMerge : clone } function getEnumerableOwnPropertySymbols(target) { return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) { return target.propertyIsEnumerable(symbol) }) : [] } function getKeys(target) { return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target)) } function propertyIsOnObject(object, property) { try { return property in object } catch (_) { return false } } // 防止原型中毒和合并原型链 function propertyIsUnsafe(target, key) { return ( propertyIsOnObject(target, key) && // 如果它们存在于对象中 !( (Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key)) // 如果它们不存在于原型链上,则安全, ) ) // 属性是可枚举,则安全 } function mergeObject(target, source, options) { var destination = {} if (options.isMergeableObject(target)) { getKeys(target).forEach(function(key) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], options) }) } getKeys(source).forEach(function(key) { if (propertyIsUnsafe(target, key)) { return } // target中存在key属性,并且是可以合并的对象 if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) { destination[key] = getMergeFunction(key, options)(target[key], source[key], options) } else { destination[key] = cloneUnlessOtherwiseSpecified(source[key], options) } }) return destination } function clone(target = {}, source = {}, options = {}) { options = options || {} if (options.arrayMerge !== undefined) { if (getType(options.arrayMerge) === '[object Function]') { // options.arrayMerge = options.arrayMerge } else if (options.arrayMerge === false) { options.arrayMerge = indexArrayMerge } else { options.arrayMerge = defaultArrayMerge } } else { options.arrayMerge = defaultArrayMerge } if (options.isMergeableObject === undefined || getType(options.isMergeableObject) !== '[object Function]') { options.isMergeableObject = defaultIsMergeableObject } // options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge() // implementations can use it. The caller may not replace it. options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified var sourceIsArray = Array.isArray(source) var targetIsArray = Array.isArray(target) var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray if (!sourceAndTargetTypesMatch) { // target, source 只有1个是数组 return cloneUnlessOtherwiseSpecified(source, options) } else if (sourceIsArray) { // target, source 都是数组 return options.arrayMerge(target, source, options) } else { // target, source 都不是数组 return mergeObject(target, source, options) } } function cloneAll(array = [{}, {}], options) { if (!Array.isArray(array)) { throw new Error('first argument should be an array') } if (array.length == 0) { return {} } else if (array.length == 1) { return clone(array[0], {}, options) } return array.reduce(function(prev, next) { return clone(prev, next, options) }, {}) } function merge(...rest) { if (!Array.isArray(rest)) { throw new Error('first argument should be an array') } if (rest.length == 0) { return {} } else if (rest.length == 1) { return clone(rest[0], {}, options) } return rest.reduce(function(prev, next) { return clone(prev, next, options) }, {}) } export default { clone, cloneAll, merge }