DigitalConsumer.ISS/src/helpers/object-helper.js

88 lines
2.7 KiB
JavaScript

// For nested objects, spread operator only creates new references to the top level fields,
// the remaining nested fields actually reference the original object which can introduce problems.
// The purpose of this method is to deep clone the data in an object recursively, this is useful
// for cloning modelValues to internal models when regular two-way binding is not an option.
// See: mobile-location-modal-questions.vue
// Creates a deep clone of an object. Clones primitives, arrays and objects, excluding class instances.
// https://www.30secondsofcode.org/js/s/deep-clone
export function deepClone(object) {
if (object === null) {
return null;
}
const clone = { ...object };
Object.keys(clone).forEach((key) =>
(clone[key] = typeof object[key] === 'object' ? deepClone(object[key]) : object[key]));
if (Array.isArray(object)) {
clone.length = object.length;
return Array.from(clone);
}
return clone;
}
// The purpose of this method is to check for array or object equality recursively to determine if two complex objects are equal.
// This is only a comparison of data, not functions.
export function deepEqual(obj1, obj2) {
if (typeof obj1 !== typeof obj2) {
return false;
}
if (obj1 === null || obj2 === null) {
return obj1 === obj2;
}
if (Array.isArray(obj1) && Array.isArray(obj2)) {
if (obj1.length !== obj2.length) {
return false;
}
const sorted1 = obj1.slice().sort();
const sorted2 = obj2.slice().sort();
for (let i = 0; i < sorted1.length; i++) {
if (!deepEqual(sorted1[i], sorted2[i])) {
return false;
}
}
return true;
}
if (typeof obj1 === 'object' && typeof obj2 === 'object') {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
const sortedKeys1 = keys1.sort();
const sortedKeys2 = keys2.sort();
for (let i = 0; i < sortedKeys1.length; i++) {
const key1 = sortedKeys1[i];
const key2 = sortedKeys2[i];
if (key1 !== key2 || !deepEqual(obj1[key1], obj2[key2])) {
return false;
}
}
return true;
}
return obj1 === obj2;
}
export function getPropertyCaseInsensitive(obj, property) {
const props = [];
for (const i in obj) if (Object.prototype.hasOwnProperty.call(obj, i)) props.push(i);
let prop;
// eslint-disable-next-line no-cond-assign
while (prop = props.pop()) if (prop.toLowerCase() === property.toLowerCase()) return prop;
return null;
}