bootstrap-table
Version:
An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
160 lines (134 loc) • 4.18 kB
JavaScript
/**
* Object manipulation utilities.
*
* This module provides utility functions for working with plain JavaScript objects,
* including deep copying, merging, comparing, and checking object properties.
*
* @module utils/object
*/
/**
* Checks if a value is a plain object.
*
* @param {*} obj - The value to check.
* @returns {boolean} True if the value is a plain object, false otherwise.
*/
export function isObject (obj) {
if (typeof obj !== 'object' || obj === null) {
return false
}
let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
}
// $.extend: https://github.com/jquery/jquery/blob/3.6.2/src/core.js#L132
/**
* Merges the contents of two or more objects together into the first object.
* This is a re-implementation of jQuery's extend function.
*
* @param {boolean} [deep=false] - If true, the merge becomes recursive (deep copy).
* @param {Object} target - The object to extend.
* @param {...Object} objects - The objects to merge into the target.
* @returns {Object} The extended target object.
*/
export function extend (...args) {
let target = args[0] || {}
let i = 1
let deep = false
let clone
// Handle a deep copy situation
if (typeof target === 'boolean') {
deep = target
// Skip the boolean and the target
target = args[i] || {}
i++
}
// Handle case when target is a string or something (possible in deep copy)
if (typeof target !== 'object' && typeof target !== 'function') {
target = {}
}
for (; i < args.length; i++) {
const options = args[i]
// Ignore undefined/null values
if (typeof options === 'undefined' || options === null) {
continue
}
// Extend the base object
// eslint-disable-next-line guard-for-in
for (const name in options) {
const copy = options[name]
// Prevent Object.prototype pollution
// Prevent never-ending loop
if (name === '__proto__' || target === copy) {
continue
}
const copyIsArray = Array.isArray(copy)
// Recurse if we're merging plain objects or arrays
if (deep && copy && (isObject(copy) || copyIsArray)) {
const src = target[name]
if (copyIsArray && Array.isArray(src)) {
if (src.every(it => !isObject(it) && !Array.isArray(it))) {
target[name] = copy
continue
}
}
if (copyIsArray && !Array.isArray(src)) {
clone = []
} else if (!copyIsArray && !isObject(src)) {
clone = {}
} else {
clone = src
}
// Never move original objects, clone them
target[name] = extend(deep, clone, copy)
// Don't bring in undefined values
} else if (copy !== undefined) {
target[name] = copy
}
}
}
return target
}
/**
* Creates a deep copy of a value.
*
* @param {*} arg - The value to deep copy.
* @returns {*} A deep copy of the input value.
*/
export function deepCopy (arg) {
if (arg === undefined) {
return arg
}
return extend(true, Array.isArray(arg) ? [] : {}, arg)
}
/**
* Compares two objects for equality.
*
* @param {Object} objectA - The first object to compare.
* @param {Object} objectB - The second object to compare.
* @param {boolean} [compareLength=false] - If true, also compare the number of keys.
* @returns {boolean} True if the objects are equal, false otherwise.
*/
export function compareObjects (objectA, objectB, compareLength) {
const aKeys = Object.keys(objectA)
const bKeys = Object.keys(objectB)
if (compareLength && aKeys.length !== bKeys.length) {
return false
}
for (const key of aKeys) {
if (bKeys.includes(key) && objectA[key] !== objectB[key]) {
return false
}
}
return true
}
/**
* Checks if an object is empty (has no own properties).
*
* @param {Object} [obj={}] - The object to check.
* @returns {boolean} True if the object is empty, false otherwise.
*/
export function isEmptyObject (obj = {}) {
return Object.entries(obj).length === 0 && obj.constructor === Object
}