object.js

/** @module Object */

import { isObject } from './type'

/**
 * 对象深复制函数
 * @function deepClone
 * @param {object} obj - 深复制的源对象
 * @return {object}
 * @example
 * var a = { foo: 'bar', obj: { a: 1, b: 2 } }
 * var b = U.deepClone(a)
 * b.foo = 'foo'
 * // => a = { foo: 'bar', obj: { a: 1, b: 2 } }, b = { foo: 'foo', obj: { a: 1, b: 2 } }
 */
export const deepClone = obj => {
  let clone = Object.assign({}, obj)
  Object.keys(clone).forEach(k => {
    clone[k] = isObject(obj[k]) ? deepClone(obj[k]) : obj[k]
  })
  return Array.isArray(obj) ? (clone.length = obj.length) && Array.from(clone) : clone
}

/**
 * 对象深冻结函数
 * @function deepFreeze
 * @param {object} obj - 深冻结的源对象
 * @return {object}
 * @example
 * let arr = [1, [2, 3]]
 * const o = U.deepFreeze(arr)
 * o[0] = 3
 * o[1][0] = 4
 * // => arr = [1, [2, 3]], o = [1, [2, 3]]
 */
export const deepFreeze = obj => {
  Object.keys(obj).forEach(prop => {
    if (obj[prop] instanceof Object && obj[prop] !== null) {
      deepFreeze(obj[prop])
    }
  })
  return Object.freeze(obj)
}

/**
 * 重命名对象的key名称。
 * @function renameKeys
 * @param {object} map - 由oldKey:newKey键值对组成的对象
 * @param {object} obj - 目标对象
 * @return {object}
 * @example
 * let obj = {name: 'john', job: 'fonts', detail: [1, 2]}
 * U.renameKeys({job: 'possion'}, obj)
 * // => { name: 'john', possion: 'fonts', detail: [ 1, 2 ] }
 */
export const renameKeys = (map, obj) => (
  Object.keys(obj)
    .reduce((acc, key) => ({
      ...acc,
      ...{ [map[key] || key]: obj[key] }
    }), {})
)

/**
 * 从对象中省略与给定键对应的键值对。
 * @function omit
 * @param {object} obj - 目标对象
 * @param {array} arr - 省略的键名数组
 * @return {object}
 * @example
 * U.omit({ a: 1, b: '2', c: 3 }, ['b'])
 * // => { a: 1, c: 3 }
 */
export const omit = (obj, arr) => (
  Object.keys(obj)
    .filter(k => !arr.includes(k))
    .reduce((acc, key) => ((acc[key] = obj[key]), acc), {})
)

/**
 * 判断val是否是空对象。
 * @function isEmpty
 * @param {*} val - 检查的对象
 * @return {boolean}
 * @example
 * U.isEmpty(new Map()) // => true
 * U.isEmpty(new Set()) // => true
 * U.isEmpty({}) // => true
 * U.isEmpty([]) // => true
 * U.isEmpty('') // => true
 * U.isEmpty({a: 1}) // => false
 * U.isEmpty([2]) // => false
 * U.isEmpty('text') // => false
 * U.isEmpty(123) // => true
 * U.isEmpty(true) // => true
 * U.isEmpty(false) // => true
 */
export const isEmpty = val => !(Object.keys(val) || val).length

/**
 * 根据obj对象的path路径获取值。
 * @function get
 * @param {object} obj - 要检索的对象
 * @param {string} path - 要获取属性的路径
 * @return {*}
 * @example
 * const obj = {name: 'joe', child: [{name: 'john', child: null}]}
 * U.get(obj, 'child[0].name')
 * // => 'john'
 */
export const get = (obj, path) => new Function('obj', 'return obj.' + path)(obj)