Update hasKey snippet to handle failing scenario and add new tests
This commit is contained in:
@ -1,21 +1,25 @@
|
|||||||
---
|
---
|
||||||
title: hasKey
|
title: hasKey
|
||||||
tags: object,recursion,intermediate
|
tags: object,intermediate
|
||||||
---
|
---
|
||||||
|
|
||||||
Returns `true` if the target value exists in a JSON object, `false` otherwise.
|
Returns `true` if the target value exists in a JSON object, `false` otherwise.
|
||||||
|
Accepts target object as first parameter and list of string keys as second parameter.
|
||||||
|
|
||||||
Check if the key contains `.`, use `String.prototype.split('.')[0]` to get the first part and store as `_key`.
|
Check if the list of keys is non-empty and use `Array.prototype.every()` to sequentially check
|
||||||
Use `typeof` to check if the contents of `obj[key]` are an `object` and, if so, call `hasKey` with that object and the remainder of the `key`.
|
keys from given key list to internal depth of the object. Use `Object.prototype.hasOwnProperty()` to check if current object does not have
|
||||||
Otherwise, use `Object.keys(obj)` in combination with `Array.prototype.includes()` to check if the given `key` exists.
|
current key or is not an object at all then stop propagation and return `false`, else assign inner
|
||||||
|
value as the new object to `obj` to use it next time. Return `true` on completion.
|
||||||
|
|
||||||
|
Return `false` beforehand if given key list is empty.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const hasKey = (obj, key) => {
|
const hasKey = (obj, keys) => {
|
||||||
if (key.includes('.')) {
|
return (keys.length > 0) && keys.every((key) => {
|
||||||
let _key = key.split('.')[0];
|
if (typeof obj !== 'object' || !obj.hasOwnProperty(key)) return false;
|
||||||
if (typeof obj[_key] === 'object') return hasKey(obj[_key], key.slice(key.indexOf('.') + 1));
|
obj = obj[key];
|
||||||
}
|
return true;
|
||||||
return Object.keys(obj).includes(key);
|
});
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -23,12 +27,13 @@ const hasKey = (obj, key) => {
|
|||||||
let obj = {
|
let obj = {
|
||||||
a: 1,
|
a: 1,
|
||||||
b: { c: 4 },
|
b: { c: 4 },
|
||||||
'd.e': 5
|
'b.d': 5,
|
||||||
};
|
};
|
||||||
hasKey(obj, 'a'); // true
|
hasKey(obj, ['a']); // true
|
||||||
hasKey(obj, 'b'); // true
|
hasKey(obj, ['b']); // true
|
||||||
hasKey(obj, 'b.c'); // true
|
hasKey(obj, ['b', 'c']); // true
|
||||||
hasKey(obj, 'd.e'); // true
|
hasKey(obj, ['b.d']); // true
|
||||||
hasKey(obj, 'd'); // false
|
hasKey(obj, ['d']); // false
|
||||||
hasKey(obj, 'f'); // false
|
hasKey(obj, ['c']); // false
|
||||||
|
hasKey(obj, ['b', 'f']); // false
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
const {hasKey} = require('./_30s.js');
|
const {hasKey} = require('./_30s.js');
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
a: 1, b: { c: 4 }, 'd.e': 5
|
a: 1,
|
||||||
|
b: { c: 4 },
|
||||||
|
'd.e': 5,
|
||||||
|
'b.d': 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
test('hasKey is a Function', () => {
|
test('hasKey is a Function', () => {
|
||||||
@ -9,25 +12,33 @@ test('hasKey is a Function', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns true for simple property', () => {
|
test('hasKey returns true for simple property', () => {
|
||||||
expect(hasKey(data, 'a')).toBe(true);
|
expect(hasKey(data, ['a'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns true for object property', () => {
|
test('hasKey returns true for object property', () => {
|
||||||
expect(hasKey(data, 'b')).toBe(true);
|
expect(hasKey(data, ['b'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns true for nested property', () => {
|
test('hasKey returns true for nested property', () => {
|
||||||
expect(hasKey(data, 'b.c')).toBe(true);
|
expect(hasKey(data, ['b', 'c'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns true for property with dots', () => {
|
test('hasKey returns true for property with dots', () => {
|
||||||
expect(hasKey(data, 'd.e')).toBe(true);
|
expect(hasKey(data, ['d.e'])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasKey returns true for property with dots and same sibling key', () => {
|
||||||
|
expect(hasKey(data, ['b.d'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns false for non-existent property', () => {
|
test('hasKey returns false for non-existent property', () => {
|
||||||
expect(hasKey(data, 'f')).toBe(true);
|
expect(hasKey(data, ['f'])).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hasKey returns false for virtual nested property', () => {
|
test('hasKey returns false for virtual nested property', () => {
|
||||||
expect(hasKey(data, 'd')).toBe(false);
|
expect(hasKey(data, ['d'])).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasKey returns false for empty key list', () => {
|
||||||
|
expect(hasKey(data, [])).toBe(false);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user