-
-
Save dfkaye/59263b51cf1e0b633181c5f44ae2066a to your computer and use it in GitHub Desktop.
| // 28 June 2017 | |
| // Quick-and-dirty implementation. | |
| // 30 Sept 2021 | |
| // Changes prompted by @nativekar: | |
| // - Allow pathName param to be either Array or string. | |
| // - Support "value[property]" notation. | |
| // House-cleaning: | |
| // - Move the inline mocha suite to own file, replace with inline test closure. | |
| // - Add "_" inline definition for standalone test execution. | |
| // Uncomment to set _ in test environment: | |
| // var _ = globalThis._ ?? {}; | |
| /** | |
| * _.get() polyfill for q&d implementation. | |
| * lodash has _.get(data, path, defaultValue), but underscore does not. | |
| * makes data traversal so nice. | |
| * see https://lodash.com/docs/4.17.4#get | |
| */ | |
| typeof _.get == 'function' || (function() { | |
| /** | |
| * @param {object} object, The object to query. | |
| * @param {Array|string} pathName: The path of the property to get. | |
| * @param {*} [defaultValue]: Optional value to return for undefined resolved values. | |
| * @returns {*} resolved value, or default value if specified. | |
| */ | |
| var at = function get(object, pathName, defaultValue) { | |
| // Coerce pathName to a string (even it turns into "[object Object]"). | |
| var path = Array.isArray(pathName) | |
| ? pathName.join(".") | |
| : String(pathName); | |
| // Support bracket notation, e.g., "a[0].b.c". | |
| var match = /\[\\?("|')?(\w|d)+\\?("|')?\]/g; | |
| var parts = path | |
| .replace(match, (m, i, v) => "." + v) | |
| .split('.'); | |
| var length = parts.length; | |
| var i = 0; | |
| // In case object isn't a real object, set it to undefined. | |
| var value = object === Object(object) ? object : undefined; | |
| while (value != null && i < length) { | |
| value = value[parts[i++]]; | |
| } | |
| /** | |
| * lodash.get() returns the resolved value if | |
| * 1. iteration happened (i > 0) | |
| * 2. iteration completed (i === length) | |
| * 3. the value at the path is found in the data structure (not undefined). Note that if the path is found but the | |
| * value is null, then null is returned. | |
| * If any of those checks fails, return the defaultValue param, if provided. | |
| */ | |
| return i && i === length && value !== undefined ? value : defaultValue; | |
| }; | |
| _.get = at; | |
| }()); | |
| /* test it out */ | |
| ~(function suite() { | |
| // suite replaces inline mocha suite which has been moved to its own file. | |
| var data = { a: { b: { c: { d: 'hello' } } } }; | |
| var defaultValue = "I'm the default value"; | |
| var unresolved = 'not resolved'; | |
| var expected = 6; | |
| var instance = Object(1); | |
| var tests = [ | |
| // should find value by pathName. | |
| _.get(data, 'a.b.c.d') === 'hello', | |
| // should return default value when pathName not resolved. | |
| _.get({}, 'a.b.c.d', defaultValue) === defaultValue, | |
| // should not resolve non-object data. | |
| _.get('1', 'toString', unresolved) === unresolved, | |
| // should not resolve with an invalid pathName. | |
| _.get({ name: 'hello' }, '', unresolved) === unresolved, | |
| // should resolve on arrays with valid index pathName. | |
| _.get([1, 2, [3, 4, [5, expected]]], '2.2.1', expected) === expected, | |
| // should resolve on coerced-to-an-object with valid pathName. | |
| _.get(instance, 'toString').call(instance) === "1", | |
| // should resolve pathName as an Array of descendant property names. | |
| _.get(data, ['a', 'b', 'c', 'd']) === 'hello', | |
| // should resolve pathName containing bracket property names. | |
| _.get(data, 'a["b"]["c"]["d"]') === 'hello', | |
| // should resolve pathName containing bracket property names. | |
| _.get(data, ['a["b"]', 'c', 'd']) === 'hello' | |
| ]; | |
| // Should print array with all values `true`. | |
| console.log( tests ); | |
| }()); |
| // 30 Sept 2021 | |
| // moved the inline mocha suite to own file | |
| describe('_.get() method', function() { | |
| /** | |
| * Verification of the _.get() utility method. | |
| * using mocha and chai.assert | |
| */ | |
| it('should find value by path', function (done) { | |
| var data = { | |
| a: { | |
| b: { | |
| c: { | |
| d: 'hello' | |
| } | |
| } | |
| } | |
| }; | |
| var value = _.get(data, 'a.b.c.d'); | |
| assert.equal(value, 'hello'); | |
| done(); | |
| }); | |
| it('should return default value when path not resolved', function (done) { | |
| var defaultValue = "I'm the default value"; | |
| var value = _.get({}, 'a.b.c.d', defaultValue); | |
| assert.equal(value, defaultValue); | |
| done(); | |
| }); | |
| it('should not resolve non-object data', function (done) { | |
| var unresolved = 'not resolved'; | |
| var value = _.get('1', 'toString', unresolved); | |
| assert.equal(value, unresolved); | |
| done(); | |
| }); | |
| it('should not resolve with an invalid pathString', function (done) { | |
| var unresolved = 'not resolved'; | |
| var value = _.get({ name: 'hello' }, '', unresolved); | |
| assert.equal(value, unresolved); | |
| done(); | |
| }); | |
| it('should resolve on arrays with valid index pathString', function(done) { | |
| var expected = 6; | |
| var value = _.get([1, 2, [3, 4, [5, expected]]], '2.2.1', expected); | |
| assert.equal(value, expected); | |
| done(); | |
| }); | |
| it('should resolve on coerced-to-an-object with valid pathString', function (done) { | |
| var instance = Object(1); | |
| var value = _.get(instance, 'toString'); | |
| // it's a function, try to call it | |
| assert.strictEqual(value.call(instance), '1'); | |
| assert.notStrictEqual(value.call(instance), 1); | |
| // coerced toString output | |
| assert.equal(value, 'function toString() { [native code] }'); | |
| done(); | |
| }); | |
| }); | |
The 2nd argument, pathString isn't always a String. Most of the time, it can also be an array.
@nativekar I wasn’t aware of that. But then I haven’t used this in a long time. Might fix this in a couple days.
Thanks for pointing it out.
Cheers! Look forward to the fix. (I have started working on one of mine, maybe we can compare notes)
@nativekar - OK, I've updated the method to accept arrays as pathName params, added support for value[property] notation, and redone the inline tests as a closure (and moved the mocha suite to its own file). Let me know if you have questions.
@dfkaye - this looks perfect. Thanks for working on this.
@nativekar - Thanks. So, I looked up underscore docs to see if they had a get method now - turns out they do - https://underscorejs.org/#get - oh well…
using this, thanks!