0

I have the following object:

const foo = {
   prop1: 'I am a string',
   prop2: [
           { prop2_1: 'I am a sub string' },
           { prop2_2: 'I am a sub string' },
   ],
   prop3: 'I am a string',
   prop4: [
           { prop4_1: 'I am a sub string' },
           { prop4_2: 'I am a sub string' },
   ],
}

In JavaScript (ie not jQuery), how can I loop thru foo's properties and determine if any of it's properties are arrays? I tried this with no luck:

for (const prop in foo) {
  if (prop!== undefined) {
    if (Object.prototype.toString.call(prop) === '[object Array]') {
      prop.map((child) => {
          // do something
      });
    }
  }
}
3
  • You mean recursively? i.e. are there ever sub-properties? Commented Nov 22, 2015 at 22:44
  • yes, sorry for the omission Commented Nov 22, 2015 at 22:46
  • prop is always a string, I think you meant foo[prop] Commented Nov 22, 2015 at 22:46

2 Answers 2

3

You want Array.isArray.

You may need to polyfill this.

Non-recursive

Object.keys(foo).some((k) => Array.isArray(foo[k]));

Recursive

function containsArr(o) {
    for (var k of Object.keys(o)) {
        if (recursive(o[k])) {
            if (containsArr(o[k])) {
                return true;
            }
            continue;
        }

        if (Array.isArray(o[k])) {
            return true;
        }
    }

    return false;
}

// We recurse into functions 
// and plain objects.
function recursive(o) {
    return /^\[object (Object)| (Function)\]/
      .test(Object.prototype.toString.call(o));
}
Sign up to request clarification or add additional context in comments.

4 Comments

Care to share an example of doing ti recursively? ;)
In this case, wouldn't c be a key and not a value meaning it's always a string?
The first statement should be more efficient using some or every so that it exits as soon as the result is known, e.g. Object.keys(foo).some(x => Array.isArray(foo[x])), which is also less to type. ;-)
StackOverflow, being clickish, has many who want to show off and few who want to help.
0

two errors

firstly, const prop will fail, because a const is constant

secondly, prop is the key, so it will never be an array

the corrected code is

for (let prop in foo) {
  if (foo.hasOwnProperty(prop)) {
    if (Object.prototype.toString.call(foo[prop]) === '[object Array]') {
      foo[prop].map((child) => {
          // do something
      });
    }
  }
}

10 Comments

Thanks, the better answer!
it works now, but with using EcmaScript6 and EsLint, const was the correct pointer
const was the correct pointer ?? I don't understand what you mean - using const would mean in node prop is always prop1, or an error in firefox (yes, firefox does understand const, just doesn't like you trying to assign a value to it more than once)
babel converts it to var in the end
for (const prop in obj) actually works because in each iteration there is a new prop "variable". It's not reassigned.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.