views:

116

answers:

5

I want to be able to pass either a string literal,

'this is a string'

or a javascript object,

{one: 'this', two: 'is', three: 'a', four: 'string' }

as argument to a function, and take different actions depending on whether it's a string or an object. How do I determine which is true?

To be specific, I want to iterate over the properties of an object, and do some parsing if a property is a string, but nest recursively if the property is an object. I've figured out how to use $.each() to iterate over the properties of the object, but if I just do this with the string, it treates the string as an array of letters rather than as a single thing. Can I get around this some other way?

+2  A: 

Try the typeof operator. It will return object for objects and string for strings.

Anders Lindahl
+4  A: 
var a = 'this is a string';

console.log(typeof a);   // Displays: "string"

var b = {one: 'this', two: 'is', three: 'a', four: 'string' };

console.log(typeof b);   // Displays: "object"

Therefore:

if (typeof yourArgument === 'string') {
   // Do the string parsing
}
else if (typeof yourArgument === 'object') {
   // Do the property enumeration
}
else {
   // Throw exception
}

UPDATE:

Some further considerations:

  1. See @Andy E's comment below.

  2. typeof null returns "object" as well. The same applies to any other object, including arrays.

Daniel Vassallo
+1, because the OP asked specifically about string literals, but remember that `typeof new String("Hello") == "object"`. To be absolutely certain, use `a.constructor == String`.
Andy E
You cannot distinguish between `objects` / `arrays` and `null` with typeof.
jAndy
@jAndy: Yes true. I stated that in my answer.
Daniel Vassallo
+4  A: 

Try this:

function some_function(argument) {
  if (typeof(argument) == "string" || argument.constructor == String) {
    // it's a string literal
  } else if (argument && typeof(argument) == "object" && argument.constructor != Array) {
    // it's an object and not null
  } else {
    // error
  }
}

Thanks to Andy E for the tipp with argument.constructor.

jigfox
what's the down vote for? I would appreciate a comment! So I know what I've done wrong.
jigfox
@Jens F. I agree. Good answer. A down vote here is utterly useless. Have a +1 from me :-)
James Wiseman
this will fail calling `some_function(null)`, since `typeof(null) === 'object'`.
jAndy
@jAndy. you're a little bit late, I've already updated my code.
jigfox
@Jens F.: indeed, but still `typeof` does not know wheter it is an array or a true object.
jAndy
@jAndy, Thank you, I'm always happy to learn while answering questions!
jigfox
+4  A: 
var data = {
    foo: "I'm a string literal",
    bar:  {
       content: "I'm within an object"
    }        
};

jQuery

$.each(data, function(i, element){
    if($.isPlainObject(element){
       // we got an object here
    }
});

There are similar methods like $.isArray() or $.isFunction() within the jQuery lib.

Native Javascript

for(var element in data){
   if(toString.call(element) === '[object Object]'){
      // we got an object here
   }
}

To use the hack'ish way with toString has the advantage, that you can identify whether it is really an object and an array. Both, objects and arrays would return object by using typeof element.

Long story short, you cannot rely on the typeof operator to distinguish true objects and arrays. For that you need the toString.call(). If you just need to know whether it is any object or not, typeof is just fine.

jAndy
To anyone wondering why I marked this answer correct rather than one of those with more votes: In this answer there's a suggestion on how to meet my needs using jQuery, which means I don't have to write (or understand in detail) any implementation to use it. This answer also gives good options for covering functions and arrays.
Tomas Lycken
+1  A: 

you can do something like this

function something(variableX){
  if (typeof(variableX) === 'object'){
     // Do something
  }else if (typeof(variableX) === 'string'){
     // Do something
  }

}
AutomatedTester
you should go for an `else if`...
Andreas Niedermair
updated! thanks for that
AutomatedTester