I have an object obj which has n number of possible properties
lets say some of them are known,
const someKnownProps = ["props.abc", "xyz"]; // or more
I want to know if obj has other than known properties in it.
To clarify:
obj can look like this:
obj = {
props: {
abc: {
def: 1
},
ghi: {
jkl: 2
}
},
xyz: 3
}
Doing Object.keys only return first level children, in this case it will return props not props.abc
CodePudding user response:
You can use Object.keys
to get all keys and filter
the keys which aren't included
in the someKnownProps
array.
const obj = {
"props.abc": 1,
"xyz": 2,
"three": 3,
"four": 4,
}
const someKnownProps = ["props.abc", "xyz"]; // or more
const unknownKeys = Object.keys(obj).filter(key => !someKnownProps.includes(key))
console.log(unknownKeys)
CodePudding user response:
Similar to what Mina said:
let obj = {one: 1, two: 2, three: 3};
let knownKeys = ['one', 'two'];
for (let key in obj) {
if (!knownKeys.includes(key)) {
console.log(key);
}
}
CodePudding user response:
There are two (unrelated) tasks involved in this question:
- Traversal of an object's properties
- Comparison of a set of traversed object properties to a list of strings representing dot-notation-formatted object property accessors
While I'm sure the former has been previously discussed on SO, I'll provide an implementation of such an algorithm below in order to address the details of this question.
This is essentially a specific case of recursion where each cycle starts with these inputs:
- an object
- a dot-notation-formatted path
- a
Set
of existing such paths
The code below includes inline comments explaining what's happening, and there are some console.log
statements at the end to help you visualize some example results based on the data in your question. If something is unclear after reviewing the code, feel free to leave a comment.
'use strict';
/** @returns whether value is a non-null, non-array object */
function isObject (value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
/** @returns the enumerable (optionally including inherited) keys of an object */
function getKeys (obj, includeInherited = false) {
if (!includeInherited) return Object.keys(obj);
const keys = new Set();
let o = obj;
while (o !== null) {
for (const key of Object.keys(o)) keys.add(key);
o = Object.getPrototypeOf(o);
}
return [...keys];
}
/**
* @returns an array of strings representing all traversible branches
* of child objects, each formatted as a combined path of dot-notation
* property accessors
*/
function findObjectPaths (
obj,
{
includeInherited = false,
currentPath = '',
paths = new Set(),
skipReturn = false,
} = {},
) {
for (const key of getKeys(obj, includeInherited)) {
// Append the current dot-notation property accessor
// to the existing path of this object:
const path = `${currentPath}.${key}`;
// Add it to the set:
paths.add(path);
const o = obj[key];
// Recurse if the child value is an object:
if (isObject(o)) {
findObjectPaths(o, {
includeInherited,
currentPath: path,
paths,
skipReturn: true,
});
}
}
// If this is not a sub-cycle (it's the top-level invocation), then convert
// the set to an array and remove the first "." from each string
if (!skipReturn) return [...paths].map(p => p.slice(1));
}
// Use:
const obj = {
props: {
abc: {
def: 1,
},
ghi: {
jkl: 2,
},
},
xyz: 3,
};
let someKnownProps = ['props.abc', 'xyz'];
let objectPaths = findObjectPaths(obj);
let hasOtherProps = objectPaths.some(path => !someKnownProps.includes(path));
console.log(hasOtherProps); // true
// An example of all of the paths in the object above:
someKnownProps = [
'props',
'props.abc',
'props.abc.def',
'props.ghi',
'props.ghi.jkl',
'xyz',
];
objectPaths = findObjectPaths(obj);
hasOtherProps = objectPaths.some(path => !someKnownProps.includes(path));
console.log(hasOtherProps); // false
// Finally, comparing the results of inherited vs non-inherited enumeration:
const objWithoutOwnProps = Object.create({
props: {
abc: {
def: 1,
},
ghi: {
jkl: 2,
},
},
xyz: 3,
});
console.log(
'Non-inherited props:',
findObjectPaths(objWithoutOwnProps),
);
console.log(
'Inherited props:',
findObjectPaths(objWithoutOwnProps, {includeInherited: true}),
);