mix-ui
Version:
mix-ui,对于uView UI的补充和组合,用于uni-app生态的UI框架
238 lines (213 loc) • 7.37 kB
JavaScript
//#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
}