Test for existence of nested JavaScript object key
up vote
490
down vote
favorite
If I have a reference to an object:
var test = {};
that will potentially (but not immediately) have nested objects, something like:
{level1: {level2: {level3: "level3"}}};
What is the best way to test for the existence of keys in the most deeply nested objects?
alert(test.level1);
yields undefined
, but alert(test.level1.level2.level3);
fails.
I’m currently doing something like this:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
but I was wondering if there’s a better way.
javascript object nested
|
show 1 more comment
up vote
490
down vote
favorite
If I have a reference to an object:
var test = {};
that will potentially (but not immediately) have nested objects, something like:
{level1: {level2: {level3: "level3"}}};
What is the best way to test for the existence of keys in the most deeply nested objects?
alert(test.level1);
yields undefined
, but alert(test.level1.level2.level3);
fails.
I’m currently doing something like this:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
but I was wondering if there’s a better way.
javascript object nested
1
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
7
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07
|
show 1 more comment
up vote
490
down vote
favorite
up vote
490
down vote
favorite
If I have a reference to an object:
var test = {};
that will potentially (but not immediately) have nested objects, something like:
{level1: {level2: {level3: "level3"}}};
What is the best way to test for the existence of keys in the most deeply nested objects?
alert(test.level1);
yields undefined
, but alert(test.level1.level2.level3);
fails.
I’m currently doing something like this:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
but I was wondering if there’s a better way.
javascript object nested
If I have a reference to an object:
var test = {};
that will potentially (but not immediately) have nested objects, something like:
{level1: {level2: {level3: "level3"}}};
What is the best way to test for the existence of keys in the most deeply nested objects?
alert(test.level1);
yields undefined
, but alert(test.level1.level2.level3);
fails.
I’m currently doing something like this:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
but I was wondering if there’s a better way.
javascript object nested
javascript object nested
edited Mar 14 at 14:31
Xufox
9,90562848
9,90562848
asked Apr 13 '10 at 15:47
user113716
258k55399416
258k55399416
1
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
7
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07
|
show 1 more comment
1
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
7
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07
1
1
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
7
7
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07
|
show 1 more comment
48 Answers
48
active
oldest
votes
1 2
next
up vote
313
down vote
accepted
You have to do it step by step if you don't want a TypeError
, because if one of the members is null
or undefined
, and you try to access a member an exception will be thrown.
You can either simply catch
the exception, or make a function to test the existence of multiple levels, something like this:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
4
arguments
is not actually an array.Array.prototype.slice.call(arguments)
converts it to a formal array. Learn
– deefour
Nov 10 '12 at 1:00
22
this'd be a lot more efficient to dovar obj = arguments[0];
and start fromvar i = 1
instead of copying thearguments
object
– Claudiu
Oct 31 '13 at 19:45
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
In ES6 theargs
variable declaration can be removed and and...args
can be used as the second argument for thecheckNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
– Vernon
Dec 28 '16 at 15:49
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
|
show 9 more comments
up vote
306
down vote
Here is a pattern I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
@MuhammadUmer No, the point of(test || {})
is that if test is undefined, then you're doing({}.level1 || {})
. Of course,{}.level1
is undefined, so that means you're doing{}.level2
, and so on.
– Joshua Taylor
Apr 28 '15 at 16:06
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick withif(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
|
show 8 more comments
up vote
207
down vote
Update
Looks like lodash has added _.get
for all your nested property getting needs.
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
Previous answer
lodash users may enjoy lodash.contrib which has a couple methods that mitigate this problem.
getPath
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easilyfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
Lodash has this same functionality itself:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
|
show 3 more comments
up vote
141
down vote
I have done performance tests (thank you cdMinix for adding lodash) on some of the suggestions proposed to this question with the results listed below.
Disclaimer #1 Turning strings into references is unnecessary meta-programming and probably best avoided. Don't lose track of your references to begin with. Read more from this answer to a similar question.
Disclaimer #2 We are talking about millions of operations per millisecond here. It is very unlikely any of these would make much difference in most use cases. Choose whichever makes the most sense knowing the limitations of each. For me I would go with something like
reduce
out of convenience.
Object Wrap (by Oliver Steele) – 34 % – fastest
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
validChain – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 100% – slowest
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
what about lodash_.get()
? how performant is it comparing to those answers?
– beniutek
May 31 '17 at 14:07
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go forreduce
ortry/catch
out of convenience.
– unitario
Aug 30 '17 at 6:36
|
show 1 more comment
up vote
41
down vote
You can read an object property at any depth, if you handle the name like a string: 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
It returns undefined
if any of the segments is undefined
.
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
add a comment |
up vote
23
down vote
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
If you are coding in ES6 environment (or using 6to5) then you can take advantage of the arrow function syntax:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
Regarding the performance, there is no performance penalty for using try..catch
block if the property is set. There is a performance impact if the property is unset.
Consider simply using _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
2
I think thetry-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. Thetry-catch
approach is also far clearer thanif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.
– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
add a comment |
up vote
17
down vote
how about
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
The question still remain: witch one is faster for browsers to set up a try catch or callhasOwnProperty()
n times?
– user669677
Sep 2 '13 at 12:12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
add a comment |
up vote
9
down vote
ES6 answer, thoroughly tested :)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→see Codepen with full test coverage
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare===
for the different falsys, and added test. If you have a better idea, let me know).
– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop tofalse
. And then you might want to have a value in your object set toundefined
(I know it's weird but is is JS). I made a positive false value set to'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
|
show 2 more comments
up vote
8
down vote
I tried a recursive approach:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
The ! keys.length ||
kicks out of the recursion so it doesn't run the function with no keys left to test. Tests:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
I am using it to print a friendly html view of a bunch of objects with unknown key/values, e.g.:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
add a comment |
up vote
6
down vote
You can also use tc39 optional chaining proposal together with babel 7 - tc39-proposal-optional-chaining
Code would look like this:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
add a comment |
up vote
5
down vote
I think the following script gives more readable representation.
declare a function:
var o = function(obj) { return obj || {};};
then use it like this:
if (o(o(o(o(test).level1).level2).level3)
{
}
I call it "sad clown technique" because it is using sign o(
EDIT:
here is a version for TypeScript
it gives type checks at compile time (as well as the intellisense if you use a tool like Visual Studio)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
the usage is the same:
o(o(o(o(test).level1).level2).level3
but this time intellisense works!
plus, you can set a default value:
o(o(o(o(o(test).level1).level2).level3, "none")
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
add a comment |
up vote
5
down vote
I didn't see any example of someone using Proxies
So I came up with my own.
The great thing about it is that you don't have to interpolate strings. You can actually return a chain-able object function and do some magical things with it. You can even call functions and get array indexes to check for deep objects
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
The above code works fine for synchronous stuff. But how would you test something that is asynchronous like this ajax call?
How do you test that? what if the response isn't json when it returns a 500 http error?
window.fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
sure you could use async/await to get rid of some callbacks. But what if you could do it even more magically? something that looks like this:
fetch('https://httpbin.org/get').json().headers['User-Agent']
You probably wonder where all the promise & .then
chains are... this could be blocking for all that you know... but using the same Proxy technique with promise you can actually test deeply nested complex path for it existence without ever writing a single function
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
add a comment |
up vote
4
down vote
One simple way is this:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
The try/catch
catches the cases for when any of the higher level objects such as test, test.level1, test.level1.level2 are not defined.
add a comment |
up vote
3
down vote
A shorter, ES5 version of @CMS's excellent answer:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
With a similar test:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe changesuccess = false;
toreturn false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.
– Wade
Nov 4 '16 at 20:16
add a comment |
up vote
3
down vote
Based on this answer, I came up with this generic function using ES2015
which would solve the problem
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
1
Here is my final approachfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
add a comment |
up vote
2
down vote
The answer given by CMS works fine with the following modification for null checks as well
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
add a comment |
up vote
2
down vote
Following options were elaborated starting from this answer. Same tree for both :
var o = { a: { b: { c: 1 } } };
Stop searching when undefined
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
Ensure each level one by one
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
add a comment |
up vote
2
down vote
I know this question is old, but I wanted to offer an extension by adding this to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
Now, in order to test for any property in any object you can simply do:
if( obj.has("some.deep.nested.object.somewhere") )
Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.
This won't work with array access ([0]
)
– Royi Namir
Oct 2 '15 at 15:15
add a comment |
up vote
2
down vote
I think this is a slight improvement (becomes a 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
This works because the && operator returns the final operand it evaluated (and it short-circuits).
add a comment |
up vote
2
down vote
This works with all objects and arrays :)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
this is my improved version of Brian's answer
I used _has as the property name because it can conflict with existing has property (ex: maps)
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=;
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((d+)|"(.+)"|'(.+)')]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
Here's the fiddle
add a comment |
up vote
2
down vote
Here's my take on it - most of these solutions ignore the case of a nested array as in:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
I may want to check for obj.l2[0].k
With the function below, you can do deeptest('l2[0].k',obj)
The function will return true if the object exists, false otherwise
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
add a comment |
up vote
2
down vote
Now we can also use reduce
to loop through nested keys:
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
add a comment |
up vote
2
down vote
I thought I'd add another one that I came up with today. The reason I am proud of this solution is that it avoids nested brackets that are used in many solutions such as Object Wrap (by Oliver Steele):
(in this example I use an underscore as a placeholder variable, but any variable name will work)
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
add a comment |
up vote
1
down vote
theres a function here on thecodeabode (safeRead) which will do this in a safe manner... i.e.
safeRead(test, 'level1', 'level2', 'level3');
if any property is null or undefined, an empty string is returned
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
add a comment |
up vote
1
down vote
Based on a previous comment, here is another version where the main object could not be defined either:
// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;
add a comment |
up vote
1
down vote
I wrote my own function that takes the desired path, and has a good and bad callback function.
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
Usage:
var testObject = {
level1:{
level2:{
level3:{
}
}
}
};
checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good
checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
add a comment |
up vote
1
down vote
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
add a comment |
up vote
1
down vote
I was looking for the value to be returned if the property exists, so I modified the answer by CMS above. Here's what I came up with:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
add a comment |
up vote
1
down vote
I was having the same issue and and wanted to see if I could come up with a my own solution. This accepts the path you want to check as a string.
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
return exists;
}
Here is a snippet with some logging and test cases:
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
add a comment |
up vote
1
down vote
Slight edit to this answer to allow nested arrays in the path
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
Check linked answer for usages :)
add a comment |
1 2
next
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: false,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2631001%2ftest-for-existence-of-nested-javascript-object-key%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
StackExchange.ready(function () {
$("#show-editor-button input, #show-editor-button button").click(function () {
var showEditor = function() {
$("#show-editor-button").hide();
$("#post-form").removeClass("dno");
StackExchange.editor.finallyInit();
};
var useFancy = $(this).data('confirm-use-fancy');
if(useFancy == 'True') {
var popupTitle = $(this).data('confirm-fancy-title');
var popupBody = $(this).data('confirm-fancy-body');
var popupAccept = $(this).data('confirm-fancy-accept-button');
$(this).loadPopup({
url: '/post/self-answer-popup',
loaded: function(popup) {
var pTitle = $(popup).find('h2');
var pBody = $(popup).find('.popup-body');
var pSubmit = $(popup).find('.popup-submit');
pTitle.text(popupTitle);
pBody.html(popupBody);
pSubmit.val(popupAccept).click(showEditor);
}
})
} else{
var confirmText = $(this).data('confirm-text');
if (confirmText ? confirm(confirmText) : true) {
showEditor();
}
}
});
});
48 Answers
48
active
oldest
votes
48 Answers
48
active
oldest
votes
active
oldest
votes
active
oldest
votes
1 2
next
up vote
313
down vote
accepted
You have to do it step by step if you don't want a TypeError
, because if one of the members is null
or undefined
, and you try to access a member an exception will be thrown.
You can either simply catch
the exception, or make a function to test the existence of multiple levels, something like this:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
4
arguments
is not actually an array.Array.prototype.slice.call(arguments)
converts it to a formal array. Learn
– deefour
Nov 10 '12 at 1:00
22
this'd be a lot more efficient to dovar obj = arguments[0];
and start fromvar i = 1
instead of copying thearguments
object
– Claudiu
Oct 31 '13 at 19:45
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
In ES6 theargs
variable declaration can be removed and and...args
can be used as the second argument for thecheckNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
– Vernon
Dec 28 '16 at 15:49
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
|
show 9 more comments
up vote
313
down vote
accepted
You have to do it step by step if you don't want a TypeError
, because if one of the members is null
or undefined
, and you try to access a member an exception will be thrown.
You can either simply catch
the exception, or make a function to test the existence of multiple levels, something like this:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
4
arguments
is not actually an array.Array.prototype.slice.call(arguments)
converts it to a formal array. Learn
– deefour
Nov 10 '12 at 1:00
22
this'd be a lot more efficient to dovar obj = arguments[0];
and start fromvar i = 1
instead of copying thearguments
object
– Claudiu
Oct 31 '13 at 19:45
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
In ES6 theargs
variable declaration can be removed and and...args
can be used as the second argument for thecheckNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
– Vernon
Dec 28 '16 at 15:49
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
|
show 9 more comments
up vote
313
down vote
accepted
up vote
313
down vote
accepted
You have to do it step by step if you don't want a TypeError
, because if one of the members is null
or undefined
, and you try to access a member an exception will be thrown.
You can either simply catch
the exception, or make a function to test the existence of multiple levels, something like this:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
You have to do it step by step if you don't want a TypeError
, because if one of the members is null
or undefined
, and you try to access a member an exception will be thrown.
You can either simply catch
the exception, or make a function to test the existence of multiple levels, something like this:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
edited Jan 25 '15 at 15:45
Esailija
118k14211285
118k14211285
answered Apr 13 '10 at 16:12
CMS
585k162839809
585k162839809
4
arguments
is not actually an array.Array.prototype.slice.call(arguments)
converts it to a formal array. Learn
– deefour
Nov 10 '12 at 1:00
22
this'd be a lot more efficient to dovar obj = arguments[0];
and start fromvar i = 1
instead of copying thearguments
object
– Claudiu
Oct 31 '13 at 19:45
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
In ES6 theargs
variable declaration can be removed and and...args
can be used as the second argument for thecheckNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
– Vernon
Dec 28 '16 at 15:49
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
|
show 9 more comments
4
arguments
is not actually an array.Array.prototype.slice.call(arguments)
converts it to a formal array. Learn
– deefour
Nov 10 '12 at 1:00
22
this'd be a lot more efficient to dovar obj = arguments[0];
and start fromvar i = 1
instead of copying thearguments
object
– Claudiu
Oct 31 '13 at 19:45
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
In ES6 theargs
variable declaration can be removed and and...args
can be used as the second argument for thecheckNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
– Vernon
Dec 28 '16 at 15:49
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
4
4
arguments
is not actually an array. Array.prototype.slice.call(arguments)
converts it to a formal array. Learn– deefour
Nov 10 '12 at 1:00
arguments
is not actually an array. Array.prototype.slice.call(arguments)
converts it to a formal array. Learn– deefour
Nov 10 '12 at 1:00
22
22
this'd be a lot more efficient to do
var obj = arguments[0];
and start from var i = 1
instead of copying the arguments
object– Claudiu
Oct 31 '13 at 19:45
this'd be a lot more efficient to do
var obj = arguments[0];
and start from var i = 1
instead of copying the arguments
object– Claudiu
Oct 31 '13 at 19:45
17
17
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
FYI, you can also use _.get() from lodash for this lodash.com/docs#get
– vasa
Oct 12 '15 at 21:19
3
3
In ES6 the
args
variable declaration can be removed and and ...args
can be used as the second argument for the checkNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…– Vernon
Dec 28 '16 at 15:49
In ES6 the
args
variable declaration can be removed and and ...args
can be used as the second argument for the checkNested
method. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…– Vernon
Dec 28 '16 at 15:49
2
2
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
This is a very unmaintainable. If any property keys change (they will), all devs on the project would have to 'string search' the entire codebase. This isn't really a solution to the problem, as it introduces a much bigger problem
– Drenai
Jan 14 at 11:20
|
show 9 more comments
up vote
306
down vote
Here is a pattern I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
@MuhammadUmer No, the point of(test || {})
is that if test is undefined, then you're doing({}.level1 || {})
. Of course,{}.level1
is undefined, so that means you're doing{}.level2
, and so on.
– Joshua Taylor
Apr 28 '15 at 16:06
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick withif(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
|
show 8 more comments
up vote
306
down vote
Here is a pattern I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
@MuhammadUmer No, the point of(test || {})
is that if test is undefined, then you're doing({}.level1 || {})
. Of course,{}.level1
is undefined, so that means you're doing{}.level2
, and so on.
– Joshua Taylor
Apr 28 '15 at 16:06
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick withif(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
|
show 8 more comments
up vote
306
down vote
up vote
306
down vote
Here is a pattern I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.
Here is a pattern I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.
edited Jan 14 '17 at 1:02
Ben Creasy
1,58321733
1,58321733
answered Oct 27 '10 at 14:41
Gabe Moothart
22.6k126794
22.6k126794
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
@MuhammadUmer No, the point of(test || {})
is that if test is undefined, then you're doing({}.level1 || {})
. Of course,{}.level1
is undefined, so that means you're doing{}.level2
, and so on.
– Joshua Taylor
Apr 28 '15 at 16:06
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick withif(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
|
show 8 more comments
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
@MuhammadUmer No, the point of(test || {})
is that if test is undefined, then you're doing({}.level1 || {})
. Of course,{}.level1
is undefined, so that means you're doing{}.level2
, and so on.
– Joshua Taylor
Apr 28 '15 at 16:06
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick withif(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
8
8
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
@wared I think it is interesting mostly for how concise it is. There is a detailed discussion of the performance characteristics in the linked post. Yes it always does all the tests, but it avoids creating temp vars, and you can alias {} to a var if you want to prevent the overhead of creating a new empty object each time. In 99% of cases I would not expect speed to matter, and in cases where it does there is no substitute for profiling.
– Gabe Moothart
Sep 5 '13 at 18:13
9
9
@MuhammadUmer No, the point of
(test || {})
is that if test is undefined, then you're doing ({}.level1 || {})
. Of course, {}.level1
is undefined, so that means you're doing {}.level2
, and so on.– Joshua Taylor
Apr 28 '15 at 16:06
@MuhammadUmer No, the point of
(test || {})
is that if test is undefined, then you're doing ({}.level1 || {})
. Of course, {}.level1
is undefined, so that means you're doing {}.level2
, and so on.– Joshua Taylor
Apr 28 '15 at 16:06
13
13
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick with
if(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
you said "which isn't that hard to read once you get used to it". Well, these are signs you know already this is a mess. Then why suggest this solution? It is prone to typos and gives absolutely nothing to readability. Just look it! If i have to write an ugly line, it should asswell be readable; so i'm going to just stick with
if(test.level1 && test.level1.level2 && test.level1.level2.level3)
– Sharky
Sep 30 '16 at 9:16
6
6
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
Unless I'm missing something, this won't work for boolean end-properties that might be false... sadly. Otherwise I love this idiom.
– T3db0t
Nov 17 '16 at 20:01
5
5
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
This is both hard to read and hard to type.
– pootzko
Jun 29 '17 at 9:36
|
show 8 more comments
up vote
207
down vote
Update
Looks like lodash has added _.get
for all your nested property getting needs.
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
Previous answer
lodash users may enjoy lodash.contrib which has a couple methods that mitigate this problem.
getPath
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easilyfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
Lodash has this same functionality itself:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
|
show 3 more comments
up vote
207
down vote
Update
Looks like lodash has added _.get
for all your nested property getting needs.
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
Previous answer
lodash users may enjoy lodash.contrib which has a couple methods that mitigate this problem.
getPath
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easilyfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
Lodash has this same functionality itself:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
|
show 3 more comments
up vote
207
down vote
up vote
207
down vote
Update
Looks like lodash has added _.get
for all your nested property getting needs.
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
Previous answer
lodash users may enjoy lodash.contrib which has a couple methods that mitigate this problem.
getPath
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
Update
Looks like lodash has added _.get
for all your nested property getting needs.
_.get(countries, 'greece.sparta.playwright')
https://lodash.com/docs#get
Previous answer
lodash users may enjoy lodash.contrib which has a couple methods that mitigate this problem.
getPath
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
edited Apr 26 '17 at 14:32
mikemaccana
41.5k44228292
41.5k44228292
answered Jun 4 '14 at 19:53
Austin Pray
3,92421630
3,92421630
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easilyfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
Lodash has this same functionality itself:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
|
show 3 more comments
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easilyfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
Lodash has this same functionality itself:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
Lodash really needs a _.isPathDefined(obj, pathString) method.
– Matthew Payne
Jan 9 '15 at 16:34
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easily
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
@MatthewPayne It'd be nice perhaps, but it really isn't necessary. You could do it yourself really easily
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
– Thor84no
May 12 '15 at 11:33
11
11
Lodash has this same functionality itself:
_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
Lodash has this same functionality itself:
_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
– Tom
May 15 '15 at 18:23
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
@Tom thanks. Really glad they include that by default now.
– Austin Pray
May 15 '15 at 22:56
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
even better would be _.result
– Shishir Arora
Aug 29 '15 at 8:50
|
show 3 more comments
up vote
141
down vote
I have done performance tests (thank you cdMinix for adding lodash) on some of the suggestions proposed to this question with the results listed below.
Disclaimer #1 Turning strings into references is unnecessary meta-programming and probably best avoided. Don't lose track of your references to begin with. Read more from this answer to a similar question.
Disclaimer #2 We are talking about millions of operations per millisecond here. It is very unlikely any of these would make much difference in most use cases. Choose whichever makes the most sense knowing the limitations of each. For me I would go with something like
reduce
out of convenience.
Object Wrap (by Oliver Steele) – 34 % – fastest
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
validChain – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 100% – slowest
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
what about lodash_.get()
? how performant is it comparing to those answers?
– beniutek
May 31 '17 at 14:07
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go forreduce
ortry/catch
out of convenience.
– unitario
Aug 30 '17 at 6:36
|
show 1 more comment
up vote
141
down vote
I have done performance tests (thank you cdMinix for adding lodash) on some of the suggestions proposed to this question with the results listed below.
Disclaimer #1 Turning strings into references is unnecessary meta-programming and probably best avoided. Don't lose track of your references to begin with. Read more from this answer to a similar question.
Disclaimer #2 We are talking about millions of operations per millisecond here. It is very unlikely any of these would make much difference in most use cases. Choose whichever makes the most sense knowing the limitations of each. For me I would go with something like
reduce
out of convenience.
Object Wrap (by Oliver Steele) – 34 % – fastest
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
validChain – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 100% – slowest
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
what about lodash_.get()
? how performant is it comparing to those answers?
– beniutek
May 31 '17 at 14:07
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go forreduce
ortry/catch
out of convenience.
– unitario
Aug 30 '17 at 6:36
|
show 1 more comment
up vote
141
down vote
up vote
141
down vote
I have done performance tests (thank you cdMinix for adding lodash) on some of the suggestions proposed to this question with the results listed below.
Disclaimer #1 Turning strings into references is unnecessary meta-programming and probably best avoided. Don't lose track of your references to begin with. Read more from this answer to a similar question.
Disclaimer #2 We are talking about millions of operations per millisecond here. It is very unlikely any of these would make much difference in most use cases. Choose whichever makes the most sense knowing the limitations of each. For me I would go with something like
reduce
out of convenience.
Object Wrap (by Oliver Steele) – 34 % – fastest
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
validChain – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 100% – slowest
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
I have done performance tests (thank you cdMinix for adding lodash) on some of the suggestions proposed to this question with the results listed below.
Disclaimer #1 Turning strings into references is unnecessary meta-programming and probably best avoided. Don't lose track of your references to begin with. Read more from this answer to a similar question.
Disclaimer #2 We are talking about millions of operations per millisecond here. It is very unlikely any of these would make much difference in most use cases. Choose whichever makes the most sense knowing the limitations of each. For me I would go with something like
reduce
out of convenience.
Object Wrap (by Oliver Steele) – 34 % – fastest
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
validChain – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 100% – slowest
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
edited Oct 10 '17 at 20:37
Necreaux
6,50171940
6,50171940
answered Jan 8 '17 at 11:56
unitario
3,00932032
3,00932032
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
what about lodash_.get()
? how performant is it comparing to those answers?
– beniutek
May 31 '17 at 14:07
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go forreduce
ortry/catch
out of convenience.
– unitario
Aug 30 '17 at 6:36
|
show 1 more comment
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
what about lodash_.get()
? how performant is it comparing to those answers?
– beniutek
May 31 '17 at 14:07
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go forreduce
ortry/catch
out of convenience.
– unitario
Aug 30 '17 at 6:36
12
12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
it should be noted that the more % a test has - the SLOWER it is
– avalanche1
Feb 3 '17 at 9:12
1
1
what about lodash
_.get()
? how performant is it comparing to those answers?– beniutek
May 31 '17 at 14:07
what about lodash
_.get()
? how performant is it comparing to those answers?– beniutek
May 31 '17 at 14:07
3
3
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
Tests with _.get() - jsben.ch/7aJgK
– cdMinix
Jun 27 '17 at 7:47
1
1
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
Each method of these is slower or faster than other ones depending on situation. If all keys are found then "Object Wrap" could be fastest, but if one of the keys is not found then "Native solution/Original solution" could be faster.
– evilReiko
Aug 28 '17 at 6:55
1
1
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go for
reduce
or try/catch
out of convenience.– unitario
Aug 30 '17 at 6:36
@evilReiko Any method will be slower if no keys are found but in proportion to each other it's still pretty much the same. However, you are right – this is more of an intellectual exercise than anything else. We are talking about a million iterations per millisecond here. I see no use case where it would make much difference. Me personally I would go for
reduce
or try/catch
out of convenience.– unitario
Aug 30 '17 at 6:36
|
show 1 more comment
up vote
41
down vote
You can read an object property at any depth, if you handle the name like a string: 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
It returns undefined
if any of the segments is undefined
.
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
add a comment |
up vote
41
down vote
You can read an object property at any depth, if you handle the name like a string: 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
It returns undefined
if any of the segments is undefined
.
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
add a comment |
up vote
41
down vote
up vote
41
down vote
You can read an object property at any depth, if you handle the name like a string: 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
It returns undefined
if any of the segments is undefined
.
You can read an object property at any depth, if you handle the name like a string: 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
It returns undefined
if any of the segments is undefined
.
edited Nov 28 '14 at 0:49
answered Apr 13 '10 at 16:56
kennebec
77.7k1886115
77.7k1886115
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
add a comment |
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
3
3
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
Worth noting that this method is very performant, at least in Chrome, in some cases outperforming @Claudiu modified version of selected answer. See performance test here: jsperf.com/check-if-deep-property-exists-with-willnotthrow
– netpoetica
Nov 27 '14 at 5:32
add a comment |
up vote
23
down vote
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
If you are coding in ES6 environment (or using 6to5) then you can take advantage of the arrow function syntax:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
Regarding the performance, there is no performance penalty for using try..catch
block if the property is set. There is a performance impact if the property is unset.
Consider simply using _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
2
I think thetry-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. Thetry-catch
approach is also far clearer thanif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.
– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
add a comment |
up vote
23
down vote
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
If you are coding in ES6 environment (or using 6to5) then you can take advantage of the arrow function syntax:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
Regarding the performance, there is no performance penalty for using try..catch
block if the property is set. There is a performance impact if the property is unset.
Consider simply using _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
2
I think thetry-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. Thetry-catch
approach is also far clearer thanif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.
– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
add a comment |
up vote
23
down vote
up vote
23
down vote
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
If you are coding in ES6 environment (or using 6to5) then you can take advantage of the arrow function syntax:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
Regarding the performance, there is no performance penalty for using try..catch
block if the property is set. There is a performance impact if the property is unset.
Consider simply using _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
If you are coding in ES6 environment (or using 6to5) then you can take advantage of the arrow function syntax:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
Regarding the performance, there is no performance penalty for using try..catch
block if the property is set. There is a performance impact if the property is unset.
Consider simply using _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
edited Jan 31 '16 at 13:06
answered Nov 18 '14 at 9:06
Gajus
28.8k35172311
28.8k35172311
2
I think thetry-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. Thetry-catch
approach is also far clearer thanif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.
– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
add a comment |
2
I think thetry-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. Thetry-catch
approach is also far clearer thanif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.
– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
2
2
I think the
try-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. The try-catch
approach is also far clearer than if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.– yangmillstheory
Jan 31 '16 at 3:39
I think the
try-catch
approach is the best answer. There's a philosophical difference between querying an object for its type, and assuming the API exists and failing accordingly if it doesn't. The latter is more appropriate in loosely typed languages. See stackoverflow.com/a/408305/2419669. The try-catch
approach is also far clearer than if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.– yangmillstheory
Jan 31 '16 at 3:39
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
Out of all the answers on StackOverflow, this answer actually worked. And i tried them all for various nested object properties and key values existence checks. Thanks!
– Jonathan Marzullo
Jul 19 '16 at 15:30
add a comment |
up vote
17
down vote
how about
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
The question still remain: witch one is faster for browsers to set up a try catch or callhasOwnProperty()
n times?
– user669677
Sep 2 '13 at 12:12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
add a comment |
up vote
17
down vote
how about
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
The question still remain: witch one is faster for browsers to set up a try catch or callhasOwnProperty()
n times?
– user669677
Sep 2 '13 at 12:12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
add a comment |
up vote
17
down vote
up vote
17
down vote
how about
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
how about
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
answered Apr 13 '10 at 16:09
user187291
45k1677126
45k1677126
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
The question still remain: witch one is faster for browsers to set up a try catch or callhasOwnProperty()
n times?
– user669677
Sep 2 '13 at 12:12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
add a comment |
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
The question still remain: witch one is faster for browsers to set up a try catch or callhasOwnProperty()
n times?
– user669677
Sep 2 '13 at 12:12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
13
13
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I don't think try/catch is a good way to test for existence of an object: try/catch is meant to handle exceptions, not normal conditions such as the test here. I think (typeof foo == "undefined") at each step is better -- and in general, there's probably some refactoring required if you're working with such deeply nested properties. Also, try/catch will cause a break in Firebug (and in any browser where break-on-error is turned on) if an exception is thrown.
– Sam Dutton
Nov 9 '10 at 12:00
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
I vote on this, because browser will check the existence twice if you use other solutions. Lets say you want to call ´a.c.b = 2´. Browser has to check the existence before modifying the value (otherwise it would be a memory error caught by OS).
– user669677
Sep 2 '13 at 12:04
4
4
The question still remain: witch one is faster for browsers to set up a try catch or call
hasOwnProperty()
n times?– user669677
Sep 2 '13 at 12:12
The question still remain: witch one is faster for browsers to set up a try catch or call
hasOwnProperty()
n times?– user669677
Sep 2 '13 at 12:12
12
12
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
Why is this bad again? This looks cleanest to me.
– Austin Pray
Jun 4 '14 at 19:26
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
I would say: If you expect that the property exist than it is okay to wrap it into a try block. If it then doesn't exist it is an error. But if you're just lazy and put regular code into the catch block for the case that the property doesn't exist try/catch is misused. Here a if/else or something similar is required.
– robsch
Aug 9 '16 at 13:55
add a comment |
up vote
9
down vote
ES6 answer, thoroughly tested :)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→see Codepen with full test coverage
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare===
for the different falsys, and added test. If you have a better idea, let me know).
– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop tofalse
. And then you might want to have a value in your object set toundefined
(I know it's weird but is is JS). I made a positive false value set to'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
|
show 2 more comments
up vote
9
down vote
ES6 answer, thoroughly tested :)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→see Codepen with full test coverage
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare===
for the different falsys, and added test. If you have a better idea, let me know).
– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop tofalse
. And then you might want to have a value in your object set toundefined
(I know it's weird but is is JS). I made a positive false value set to'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
|
show 2 more comments
up vote
9
down vote
up vote
9
down vote
ES6 answer, thoroughly tested :)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→see Codepen with full test coverage
ES6 answer, thoroughly tested :)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→see Codepen with full test coverage
answered May 31 at 12:58
Frank Nocke
4,1873659
4,1873659
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare===
for the different falsys, and added test. If you have a better idea, let me know).
– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop tofalse
. And then you might want to have a value in your object set toundefined
(I know it's weird but is is JS). I made a positive false value set to'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
|
show 2 more comments
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare===
for the different falsys, and added test. If you have a better idea, let me know).
– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop tofalse
. And then you might want to have a value in your object set toundefined
(I know it's weird but is is JS). I made a positive false value set to'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
I made your tests failed setting the value of the flat prop to 0. You must care about type coercion.
– germain
Oct 2 at 7:13
@germain Does this work for you? (I explicitly compare
===
for the different falsys, and added test. If you have a better idea, let me know).– Frank Nocke
Oct 2 at 11:22
@germain Does this work for you? (I explicitly compare
===
for the different falsys, and added test. If you have a better idea, let me know).– Frank Nocke
Oct 2 at 11:22
I made your tests failed again setting the value of the flat prop to
false
. And then you might want to have a value in your object set to undefined
(I know it's weird but is is JS). I made a positive false value set to 'Prop not Found'
: const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
I made your tests failed again setting the value of the flat prop to
false
. And then you might want to have a value in your object set to undefined
(I know it's weird but is is JS). I made a positive false value set to 'Prop not Found'
: const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
– germain
Oct 2 at 15:19
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Can you fork my codepen (top-right, easy), correct & add tests, and send me the URL of yours? Thanks =)
– Frank Nocke
Oct 3 at 18:16
Check this
– germain
Oct 4 at 5:01
Check this
– germain
Oct 4 at 5:01
|
show 2 more comments
up vote
8
down vote
I tried a recursive approach:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
The ! keys.length ||
kicks out of the recursion so it doesn't run the function with no keys left to test. Tests:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
I am using it to print a friendly html view of a bunch of objects with unknown key/values, e.g.:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
add a comment |
up vote
8
down vote
I tried a recursive approach:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
The ! keys.length ||
kicks out of the recursion so it doesn't run the function with no keys left to test. Tests:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
I am using it to print a friendly html view of a bunch of objects with unknown key/values, e.g.:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
add a comment |
up vote
8
down vote
up vote
8
down vote
I tried a recursive approach:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
The ! keys.length ||
kicks out of the recursion so it doesn't run the function with no keys left to test. Tests:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
I am using it to print a friendly html view of a bunch of objects with unknown key/values, e.g.:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
I tried a recursive approach:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
The ! keys.length ||
kicks out of the recursion so it doesn't run the function with no keys left to test. Tests:
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
I am using it to print a friendly html view of a bunch of objects with unknown key/values, e.g.:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
answered Nov 7 '13 at 23:00
jrode
32137
32137
add a comment |
add a comment |
up vote
6
down vote
You can also use tc39 optional chaining proposal together with babel 7 - tc39-proposal-optional-chaining
Code would look like this:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
add a comment |
up vote
6
down vote
You can also use tc39 optional chaining proposal together with babel 7 - tc39-proposal-optional-chaining
Code would look like this:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
add a comment |
up vote
6
down vote
up vote
6
down vote
You can also use tc39 optional chaining proposal together with babel 7 - tc39-proposal-optional-chaining
Code would look like this:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
You can also use tc39 optional chaining proposal together with babel 7 - tc39-proposal-optional-chaining
Code would look like this:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
answered Jun 14 at 7:59
Goran.it
3,20711620
3,20711620
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
add a comment |
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Note that this syntax will almost certainly change, as some TC39 members have objections.
– jhpratt
Sep 24 at 1:59
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
Probably but this will be available in some form in time, and that's the only thing that matters .. It's one of the features I miss the most in JS.
– Goran.it
Sep 24 at 7:00
add a comment |
up vote
5
down vote
I think the following script gives more readable representation.
declare a function:
var o = function(obj) { return obj || {};};
then use it like this:
if (o(o(o(o(test).level1).level2).level3)
{
}
I call it "sad clown technique" because it is using sign o(
EDIT:
here is a version for TypeScript
it gives type checks at compile time (as well as the intellisense if you use a tool like Visual Studio)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
the usage is the same:
o(o(o(o(test).level1).level2).level3
but this time intellisense works!
plus, you can set a default value:
o(o(o(o(o(test).level1).level2).level3, "none")
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
add a comment |
up vote
5
down vote
I think the following script gives more readable representation.
declare a function:
var o = function(obj) { return obj || {};};
then use it like this:
if (o(o(o(o(test).level1).level2).level3)
{
}
I call it "sad clown technique" because it is using sign o(
EDIT:
here is a version for TypeScript
it gives type checks at compile time (as well as the intellisense if you use a tool like Visual Studio)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
the usage is the same:
o(o(o(o(test).level1).level2).level3
but this time intellisense works!
plus, you can set a default value:
o(o(o(o(o(test).level1).level2).level3, "none")
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
add a comment |
up vote
5
down vote
up vote
5
down vote
I think the following script gives more readable representation.
declare a function:
var o = function(obj) { return obj || {};};
then use it like this:
if (o(o(o(o(test).level1).level2).level3)
{
}
I call it "sad clown technique" because it is using sign o(
EDIT:
here is a version for TypeScript
it gives type checks at compile time (as well as the intellisense if you use a tool like Visual Studio)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
the usage is the same:
o(o(o(o(test).level1).level2).level3
but this time intellisense works!
plus, you can set a default value:
o(o(o(o(o(test).level1).level2).level3, "none")
I think the following script gives more readable representation.
declare a function:
var o = function(obj) { return obj || {};};
then use it like this:
if (o(o(o(o(test).level1).level2).level3)
{
}
I call it "sad clown technique" because it is using sign o(
EDIT:
here is a version for TypeScript
it gives type checks at compile time (as well as the intellisense if you use a tool like Visual Studio)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
the usage is the same:
o(o(o(o(test).level1).level2).level3
but this time intellisense works!
plus, you can set a default value:
o(o(o(o(o(test).level1).level2).level3, "none")
edited Jan 13 '17 at 0:16
answered Feb 3 '16 at 5:45
VeganHunter
1,510199
1,510199
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
add a comment |
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
°0o <°(())))><
– DanFromGermany
Nov 17 '16 at 14:23
add a comment |
up vote
5
down vote
I didn't see any example of someone using Proxies
So I came up with my own.
The great thing about it is that you don't have to interpolate strings. You can actually return a chain-able object function and do some magical things with it. You can even call functions and get array indexes to check for deep objects
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
The above code works fine for synchronous stuff. But how would you test something that is asynchronous like this ajax call?
How do you test that? what if the response isn't json when it returns a 500 http error?
window.fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
sure you could use async/await to get rid of some callbacks. But what if you could do it even more magically? something that looks like this:
fetch('https://httpbin.org/get').json().headers['User-Agent']
You probably wonder where all the promise & .then
chains are... this could be blocking for all that you know... but using the same Proxy technique with promise you can actually test deeply nested complex path for it existence without ever writing a single function
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
add a comment |
up vote
5
down vote
I didn't see any example of someone using Proxies
So I came up with my own.
The great thing about it is that you don't have to interpolate strings. You can actually return a chain-able object function and do some magical things with it. You can even call functions and get array indexes to check for deep objects
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
The above code works fine for synchronous stuff. But how would you test something that is asynchronous like this ajax call?
How do you test that? what if the response isn't json when it returns a 500 http error?
window.fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
sure you could use async/await to get rid of some callbacks. But what if you could do it even more magically? something that looks like this:
fetch('https://httpbin.org/get').json().headers['User-Agent']
You probably wonder where all the promise & .then
chains are... this could be blocking for all that you know... but using the same Proxy technique with promise you can actually test deeply nested complex path for it existence without ever writing a single function
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
add a comment |
up vote
5
down vote
up vote
5
down vote
I didn't see any example of someone using Proxies
So I came up with my own.
The great thing about it is that you don't have to interpolate strings. You can actually return a chain-able object function and do some magical things with it. You can even call functions and get array indexes to check for deep objects
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
The above code works fine for synchronous stuff. But how would you test something that is asynchronous like this ajax call?
How do you test that? what if the response isn't json when it returns a 500 http error?
window.fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
sure you could use async/await to get rid of some callbacks. But what if you could do it even more magically? something that looks like this:
fetch('https://httpbin.org/get').json().headers['User-Agent']
You probably wonder where all the promise & .then
chains are... this could be blocking for all that you know... but using the same Proxy technique with promise you can actually test deeply nested complex path for it existence without ever writing a single function
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
I didn't see any example of someone using Proxies
So I came up with my own.
The great thing about it is that you don't have to interpolate strings. You can actually return a chain-able object function and do some magical things with it. You can even call functions and get array indexes to check for deep objects
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
The above code works fine for synchronous stuff. But how would you test something that is asynchronous like this ajax call?
How do you test that? what if the response isn't json when it returns a 500 http error?
window.fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
sure you could use async/await to get rid of some callbacks. But what if you could do it even more magically? something that looks like this:
fetch('https://httpbin.org/get').json().headers['User-Agent']
You probably wonder where all the promise & .then
chains are... this could be blocking for all that you know... but using the same Proxy technique with promise you can actually test deeply nested complex path for it existence without ever writing a single function
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
edited Jul 27 at 14:55
Michiel
2,67622237
2,67622237
answered May 18 '17 at 12:50
Endless
11.8k64968
11.8k64968
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
add a comment |
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
If someone is interested, I've publish the async version on npm
– Endless
Sep 4 '17 at 12:09
add a comment |
up vote
4
down vote
One simple way is this:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
The try/catch
catches the cases for when any of the higher level objects such as test, test.level1, test.level1.level2 are not defined.
add a comment |
up vote
4
down vote
One simple way is this:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
The try/catch
catches the cases for when any of the higher level objects such as test, test.level1, test.level1.level2 are not defined.
add a comment |
up vote
4
down vote
up vote
4
down vote
One simple way is this:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
The try/catch
catches the cases for when any of the higher level objects such as test, test.level1, test.level1.level2 are not defined.
One simple way is this:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
The try/catch
catches the cases for when any of the higher level objects such as test, test.level1, test.level1.level2 are not defined.
answered Oct 12 '11 at 15:48
jfriend00
426k51545591
426k51545591
add a comment |
add a comment |
up vote
3
down vote
A shorter, ES5 version of @CMS's excellent answer:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
With a similar test:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe changesuccess = false;
toreturn false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.
– Wade
Nov 4 '16 at 20:16
add a comment |
up vote
3
down vote
A shorter, ES5 version of @CMS's excellent answer:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
With a similar test:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe changesuccess = false;
toreturn false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.
– Wade
Nov 4 '16 at 20:16
add a comment |
up vote
3
down vote
up vote
3
down vote
A shorter, ES5 version of @CMS's excellent answer:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
With a similar test:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
A shorter, ES5 version of @CMS's excellent answer:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
With a similar test:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
answered May 21 '12 at 9:28
mikemaccana
41.5k44228292
41.5k44228292
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe changesuccess = false;
toreturn false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.
– Wade
Nov 4 '16 at 20:16
add a comment |
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe changesuccess = false;
toreturn false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.
– Wade
Nov 4 '16 at 20:16
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
the only issue with this is if there are multiple levels of undefined keys, then you get a TypeError, e.g.
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
– JKS
Jul 19 '12 at 17:34
1
1
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
A more suitable method is every, whose value can be returned directly.
– RobG
Aug 12 '15 at 11:59
Maybe change
success = false;
to return false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.– Wade
Nov 4 '16 at 20:16
Maybe change
success = false;
to return false
. You should bail out once you know it breaks, nothing deeper can exist once it's null or undefined. This would prevent the errors on the deeper nested items, since they obviously don't exist either.– Wade
Nov 4 '16 at 20:16
add a comment |
up vote
3
down vote
Based on this answer, I came up with this generic function using ES2015
which would solve the problem
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
1
Here is my final approachfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
add a comment |
up vote
3
down vote
Based on this answer, I came up with this generic function using ES2015
which would solve the problem
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
1
Here is my final approachfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
add a comment |
up vote
3
down vote
up vote
3
down vote
Based on this answer, I came up with this generic function using ES2015
which would solve the problem
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
Based on this answer, I came up with this generic function using ES2015
which would solve the problem
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
edited May 23 '17 at 11:47
Community♦
11
11
answered Aug 15 '16 at 9:11
Alex Moldovan
1,678812
1,678812
1
Here is my final approachfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
add a comment |
1
Here is my final approachfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
1
1
Here is my final approach
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
Here is my final approach
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
– James Harrington
Nov 10 '17 at 21:45
add a comment |
up vote
2
down vote
The answer given by CMS works fine with the following modification for null checks as well
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
add a comment |
up vote
2
down vote
The answer given by CMS works fine with the following modification for null checks as well
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
add a comment |
up vote
2
down vote
up vote
2
down vote
The answer given by CMS works fine with the following modification for null checks as well
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
The answer given by CMS works fine with the following modification for null checks as well
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
answered Jun 21 '13 at 18:01
Anand Sunderraman
3,2962667128
3,2962667128
add a comment |
add a comment |
up vote
2
down vote
Following options were elaborated starting from this answer. Same tree for both :
var o = { a: { b: { c: 1 } } };
Stop searching when undefined
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
Ensure each level one by one
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
add a comment |
up vote
2
down vote
Following options were elaborated starting from this answer. Same tree for both :
var o = { a: { b: { c: 1 } } };
Stop searching when undefined
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
Ensure each level one by one
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
add a comment |
up vote
2
down vote
up vote
2
down vote
Following options were elaborated starting from this answer. Same tree for both :
var o = { a: { b: { c: 1 } } };
Stop searching when undefined
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
Ensure each level one by one
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
Following options were elaborated starting from this answer. Same tree for both :
var o = { a: { b: { c: 1 } } };
Stop searching when undefined
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
Ensure each level one by one
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
edited May 23 '17 at 10:31
Community♦
11
11
answered Sep 7 '13 at 14:04
leaf
11k43969
11k43969
add a comment |
add a comment |
up vote
2
down vote
I know this question is old, but I wanted to offer an extension by adding this to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
Now, in order to test for any property in any object you can simply do:
if( obj.has("some.deep.nested.object.somewhere") )
Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.
This won't work with array access ([0]
)
– Royi Namir
Oct 2 '15 at 15:15
add a comment |
up vote
2
down vote
I know this question is old, but I wanted to offer an extension by adding this to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
Now, in order to test for any property in any object you can simply do:
if( obj.has("some.deep.nested.object.somewhere") )
Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.
This won't work with array access ([0]
)
– Royi Namir
Oct 2 '15 at 15:15
add a comment |
up vote
2
down vote
up vote
2
down vote
I know this question is old, but I wanted to offer an extension by adding this to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
Now, in order to test for any property in any object you can simply do:
if( obj.has("some.deep.nested.object.somewhere") )
Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.
I know this question is old, but I wanted to offer an extension by adding this to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
Now, in order to test for any property in any object you can simply do:
if( obj.has("some.deep.nested.object.somewhere") )
Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.
answered Mar 24 '15 at 15:57
Brian Sidebotham
1,091714
1,091714
This won't work with array access ([0]
)
– Royi Namir
Oct 2 '15 at 15:15
add a comment |
This won't work with array access ([0]
)
– Royi Namir
Oct 2 '15 at 15:15
This won't work with array access (
[0]
)– Royi Namir
Oct 2 '15 at 15:15
This won't work with array access (
[0]
)– Royi Namir
Oct 2 '15 at 15:15
add a comment |
up vote
2
down vote
I think this is a slight improvement (becomes a 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
This works because the && operator returns the final operand it evaluated (and it short-circuits).
add a comment |
up vote
2
down vote
I think this is a slight improvement (becomes a 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
This works because the && operator returns the final operand it evaluated (and it short-circuits).
add a comment |
up vote
2
down vote
up vote
2
down vote
I think this is a slight improvement (becomes a 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
This works because the && operator returns the final operand it evaluated (and it short-circuits).
I think this is a slight improvement (becomes a 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
This works because the && operator returns the final operand it evaluated (and it short-circuits).
answered Jul 16 '15 at 19:05
Julius Musseau
3,0951522
3,0951522
add a comment |
add a comment |
up vote
2
down vote
This works with all objects and arrays :)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
this is my improved version of Brian's answer
I used _has as the property name because it can conflict with existing has property (ex: maps)
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=;
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((d+)|"(.+)"|'(.+)')]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
Here's the fiddle
add a comment |
up vote
2
down vote
This works with all objects and arrays :)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
this is my improved version of Brian's answer
I used _has as the property name because it can conflict with existing has property (ex: maps)
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=;
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((d+)|"(.+)"|'(.+)')]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
Here's the fiddle
add a comment |
up vote
2
down vote
up vote
2
down vote
This works with all objects and arrays :)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
this is my improved version of Brian's answer
I used _has as the property name because it can conflict with existing has property (ex: maps)
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=;
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((d+)|"(.+)"|'(.+)')]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
Here's the fiddle
This works with all objects and arrays :)
ex:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
this is my improved version of Brian's answer
I used _has as the property name because it can conflict with existing has property (ex: maps)
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=;
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((d+)|"(.+)"|'(.+)')]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
Here's the fiddle
edited Feb 24 '16 at 14:08
answered Jan 30 '16 at 13:37
adutu
36638
36638
add a comment |
add a comment |
up vote
2
down vote
Here's my take on it - most of these solutions ignore the case of a nested array as in:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
I may want to check for obj.l2[0].k
With the function below, you can do deeptest('l2[0].k',obj)
The function will return true if the object exists, false otherwise
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
add a comment |
up vote
2
down vote
Here's my take on it - most of these solutions ignore the case of a nested array as in:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
I may want to check for obj.l2[0].k
With the function below, you can do deeptest('l2[0].k',obj)
The function will return true if the object exists, false otherwise
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
add a comment |
up vote
2
down vote
up vote
2
down vote
Here's my take on it - most of these solutions ignore the case of a nested array as in:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
I may want to check for obj.l2[0].k
With the function below, you can do deeptest('l2[0].k',obj)
The function will return true if the object exists, false otherwise
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
Here's my take on it - most of these solutions ignore the case of a nested array as in:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
I may want to check for obj.l2[0].k
With the function below, you can do deeptest('l2[0].k',obj)
The function will return true if the object exists, false otherwise
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
edited Aug 25 '16 at 2:49
Seth
6,00663058
6,00663058
answered Nov 9 '15 at 18:24
Mike D
394
394
add a comment |
add a comment |
up vote
2
down vote
Now we can also use reduce
to loop through nested keys:
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
add a comment |
up vote
2
down vote
Now we can also use reduce
to loop through nested keys:
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
add a comment |
up vote
2
down vote
up vote
2
down vote
Now we can also use reduce
to loop through nested keys:
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
Now we can also use reduce
to loop through nested keys:
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
answered Apr 30 '17 at 18:42
Egor Stambakio
8,06141321
8,06141321
add a comment |
add a comment |
up vote
2
down vote
I thought I'd add another one that I came up with today. The reason I am proud of this solution is that it avoids nested brackets that are used in many solutions such as Object Wrap (by Oliver Steele):
(in this example I use an underscore as a placeholder variable, but any variable name will work)
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
add a comment |
up vote
2
down vote
I thought I'd add another one that I came up with today. The reason I am proud of this solution is that it avoids nested brackets that are used in many solutions such as Object Wrap (by Oliver Steele):
(in this example I use an underscore as a placeholder variable, but any variable name will work)
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
add a comment |
up vote
2
down vote
up vote
2
down vote
I thought I'd add another one that I came up with today. The reason I am proud of this solution is that it avoids nested brackets that are used in many solutions such as Object Wrap (by Oliver Steele):
(in this example I use an underscore as a placeholder variable, but any variable name will work)
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
I thought I'd add another one that I came up with today. The reason I am proud of this solution is that it avoids nested brackets that are used in many solutions such as Object Wrap (by Oliver Steele):
(in this example I use an underscore as a placeholder variable, but any variable name will work)
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//the 'test' object
var test = {level1: {level2: {level3: 'level3'}}};
let _ = test;
if ((_=_.level1) && (_=_.level2) && (_=_.level3)) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//you could also use 'stacked' if statements. This helps if your object goes very deep.
//(formatted without nesting or curly braces except the last one)
let _ = test;
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
//or you can indent:
if (_=_.level1)
if (_=_.level2)
if (_=_.level3) {
let level3 = _;
//do stuff with level3
}
edited Aug 11 '17 at 22:10
answered Jul 26 '17 at 0:19
kubakoz
363
363
add a comment |
add a comment |
up vote
1
down vote
theres a function here on thecodeabode (safeRead) which will do this in a safe manner... i.e.
safeRead(test, 'level1', 'level2', 'level3');
if any property is null or undefined, an empty string is returned
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
add a comment |
up vote
1
down vote
theres a function here on thecodeabode (safeRead) which will do this in a safe manner... i.e.
safeRead(test, 'level1', 'level2', 'level3');
if any property is null or undefined, an empty string is returned
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
add a comment |
up vote
1
down vote
up vote
1
down vote
theres a function here on thecodeabode (safeRead) which will do this in a safe manner... i.e.
safeRead(test, 'level1', 'level2', 'level3');
if any property is null or undefined, an empty string is returned
theres a function here on thecodeabode (safeRead) which will do this in a safe manner... i.e.
safeRead(test, 'level1', 'level2', 'level3');
if any property is null or undefined, an empty string is returned
answered Apr 13 '13 at 8:50
Ben
1,055118
1,055118
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
add a comment |
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
I kind of like this method with templating because it returns an empty string if not set
– Lounge9
Jan 21 '16 at 19:26
add a comment |
up vote
1
down vote
Based on a previous comment, here is another version where the main object could not be defined either:
// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;
add a comment |
up vote
1
down vote
Based on a previous comment, here is another version where the main object could not be defined either:
// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;
add a comment |
up vote
1
down vote
up vote
1
down vote
Based on a previous comment, here is another version where the main object could not be defined either:
// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;
Based on a previous comment, here is another version where the main object could not be defined either:
// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;
edited May 23 '17 at 12:34
Community♦
11
11
answered Aug 27 '13 at 21:09
Juampy NR
1,6701613
1,6701613
add a comment |
add a comment |
up vote
1
down vote
I wrote my own function that takes the desired path, and has a good and bad callback function.
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
Usage:
var testObject = {
level1:{
level2:{
level3:{
}
}
}
};
checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good
checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
add a comment |
up vote
1
down vote
I wrote my own function that takes the desired path, and has a good and bad callback function.
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
Usage:
var testObject = {
level1:{
level2:{
level3:{
}
}
}
};
checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good
checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
add a comment |
up vote
1
down vote
up vote
1
down vote
I wrote my own function that takes the desired path, and has a good and bad callback function.
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
Usage:
var testObject = {
level1:{
level2:{
level3:{
}
}
}
};
checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good
checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad
I wrote my own function that takes the desired path, and has a good and bad callback function.
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
Usage:
var testObject = {
level1:{
level2:{
level3:{
}
}
}
};
checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good
checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad
answered Mar 19 '15 at 17:55
Stephane LaFlèche
111
111
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
add a comment |
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
I though fair to give you credit for the inspiration to adapt your code to my answer
– davewoodhall
Jun 2 '16 at 20:02
add a comment |
up vote
1
down vote
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
add a comment |
up vote
1
down vote
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
add a comment |
up vote
1
down vote
up vote
1
down vote
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
answered Jul 10 '15 at 14:27
alejandro
2,16311320
2,16311320
add a comment |
add a comment |
up vote
1
down vote
I was looking for the value to be returned if the property exists, so I modified the answer by CMS above. Here's what I came up with:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
add a comment |
up vote
1
down vote
I was looking for the value to be returned if the property exists, so I modified the answer by CMS above. Here's what I came up with:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
add a comment |
up vote
1
down vote
up vote
1
down vote
I was looking for the value to be returned if the property exists, so I modified the answer by CMS above. Here's what I came up with:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
I was looking for the value to be returned if the property exists, so I modified the answer by CMS above. Here's what I came up with:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
answered Jul 25 '15 at 3:13
Noah Stahl
9911711
9911711
add a comment |
add a comment |
up vote
1
down vote
I was having the same issue and and wanted to see if I could come up with a my own solution. This accepts the path you want to check as a string.
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
return exists;
}
Here is a snippet with some logging and test cases:
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
add a comment |
up vote
1
down vote
I was having the same issue and and wanted to see if I could come up with a my own solution. This accepts the path you want to check as a string.
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
return exists;
}
Here is a snippet with some logging and test cases:
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
add a comment |
up vote
1
down vote
up vote
1
down vote
I was having the same issue and and wanted to see if I could come up with a my own solution. This accepts the path you want to check as a string.
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
return exists;
}
Here is a snippet with some logging and test cases:
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
I was having the same issue and and wanted to see if I could come up with a my own solution. This accepts the path you want to check as a string.
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
return exists;
}
Here is a snippet with some logging and test cases:
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
console.clear();
var testCases = [
["data.Messages[0].Code", true],
["data.Messages[1].Code", true],
["data.Messages[0]['Code']", true],
['data.Messages[0]["Code"]', true],
["data[Messages][0]['Code']", false],
["data['Messages'][0]['Code']", true]
];
var path = "data.Messages[0].Code";
var obj = {
data: {
Messages: [{
Code: "0"
}, {
Code: "1"
}]
}
}
function checkPathForTruthy(obj, path) {
if (/[[a-zA-Z_]/.test(path)) {
console.log("Cannot resolve variables in property accessors");
return false;
}
path = path.replace(/[/g, ".");
path = path.replace(/]|'|"/g, "");
path = path.split(".");
var steps = 0;
var lastRef = obj;
var logOutput = ;
var exists = path.every(key => {
var currentItem = lastRef[path[steps]];
if (currentItem) {
logOutput.push(currentItem);
lastRef = currentItem;
steps++;
return true;
} else {
return false;
}
});
console.log(exists, logOutput);
return exists;
}
testCases.forEach(testCase => {
if (checkPathForTruthy(obj, testCase[0]) === testCase[1]) {
console.log("Passed: " + testCase[0]);
} else {
console.log("Failed: " + testCase[0] + " expected " + testCase[1]);
}
});
edited Sep 14 '16 at 11:08
answered Sep 14 '16 at 9:50
Jonathan
5,17722154
5,17722154
add a comment |
add a comment |
up vote
1
down vote
Slight edit to this answer to allow nested arrays in the path
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
Check linked answer for usages :)
add a comment |
up vote
1
down vote
Slight edit to this answer to allow nested arrays in the path
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
Check linked answer for usages :)
add a comment |
up vote
1
down vote
up vote
1
down vote
Slight edit to this answer to allow nested arrays in the path
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
Check linked answer for usages :)
Slight edit to this answer to allow nested arrays in the path
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
Check linked answer for usages :)
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
var has = function (obj, key) {
return key.split(".").every(function (x) {
if (typeof obj != "object" || obj === null || !x in obj)
return false;
if (obj.constructor === Array)
obj = obj[0];
obj = obj[x];
return true;
});
}
answered Jun 22 '17 at 2:16
wesley chase
112
112
add a comment |
add a comment |
1 2
next
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2631001%2ftest-for-existence-of-nested-javascript-object-key%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
you might want to check a tangentially related question that was asked recently stackoverflow.com/questions/2525943/…
– Anurag
Apr 13 '10 at 16:21
See also stackoverflow.com/questions/10918488/…
– James McMahon
Dec 21 '12 at 15:38
A couple of propositions there : stackoverflow.com/a/18381564/1636522
– leaf
Sep 7 '13 at 7:27
Your current approach has a potential issue if level3 property is a false, in that case, even if the property exist will retur nfalse have a look at this example please jsfiddle.net/maz9bLjx
– GibboK
Jul 11 '15 at 6:18
7
simply you can use try catch also
– Raghavendra
Aug 12 '15 at 12:07