4

In the text adventure I am making, my object literals for the rooms look like this:

room : {
  // some info,
  exits : {
    north : -1,
    east : "house",
    south : "forest",
    west : -1
  }
}

and in my function to move around it says:

if (room["exits"][direction] !== -1) {// go that way}
else {print "you can't go that way!"}

now I want to save space by just testing if the key for the relevant direction exits in the object. so the literals will go:

room : {
  // some info,
  exits : {
    east : "house",
    south : "forest"
  }
}

... what should my if statement look like? what is the 'proper' way to ascertain if a given key-name exits in the object?

bluish
  • 26,356
  • 27
  • 122
  • 180
drenl
  • 1,321
  • 4
  • 18
  • 32
  • These all seem like good answers. Here's a related question. What does a non-key value return? Ie: in the above example, `var foo = room.exits[bar]` ... is foo null? undefined? – drenl Dec 22 '13 at 01:50
  • `room.exits[bar]` will returned `undefined` if `bar` doesn't exist. `'bar' in room.exits` will return `false`. – p.s.w.g Dec 22 '13 at 01:53
  • ok. *Challenge Question*: can you point me to a reference that explains null, undefined, and falsey (as they are applicable in this context), *that a noob would have a chance of understanding* ? – drenl Dec 22 '13 at 02:00
  • See http://stackoverflow.com/questions/5076944/what-is-the-difference-between-null-and-undefined-in-javascript and http://www.sitepoint.com/javascript-truthy-falsy/ – p.s.w.g Dec 22 '13 at 02:33
  • excellent. thank you all for the discussion! – drenl Dec 22 '13 at 02:42

3 Answers3

6

You can use the in operator:

if (direction in room.exits) {
    // go that way
} else { 
    console.log("you can't go that way!");
}
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • I'm giving you a +1 as it didn't occur to me to use this, but I found some interesting info (posted in my answer) that should be taken into consideration. – Stephen Dec 22 '13 at 01:53
  • @Stephen +1 for the interesting observation. If OP had millions of checks to perform, this would be a big concern. However, it looks to me like this is not a particularly performance critical part of an application. Both solutions seem perfectly valid. – p.s.w.g Dec 22 '13 at 01:57
  • Very true - but information like this hopefully gets tucked away for a rainy day :) – Stephen Dec 22 '13 at 01:58
3

If there's absolutely no chance that it'll be null, a blank string, zero, or any other 'falsey' JS value you can just do

if(room.exits[direction]) { // go that way }
else {print "you can't go that way!"}

I also did a speed test against the 'in' operator that p.s.w.g posted as an answer because it never really occurred to me to use it. I found some interesting results that you should consider if you're running this in any kind of loop at any point.

http://jsperf.com/test-in-operator-vs-if

It seems that the "in" operator is SIGNIFICANTLY slower on IE and Chrome, but on Firefox it's almost twice as fast.

Stephen
  • 5,362
  • 1
  • 22
  • 33
  • Hmm. Is this is contrast to akhikhl's answer, or just a different way of putting it? – drenl Dec 22 '13 at 02:05
  • Eh, it's pretty much the same - difference being that 'direction' in mine is a variable, and with akhikhl's it's being set in code. Pretty sure we just saved the same-ish code at the same time. – Stephen Dec 22 '13 at 02:06
  • yeah, I just mean using the period vs. the square braces. Pretending for the moment that he was using a variable. – drenl Dec 22 '13 at 02:26
  • There is actually a difference performance-wise. Using a variable property is more expensive than doing `room.exists.something`, however (much like p.s.w.g's answer), it improves readability vs. what looks like otherwise a minimum of four different possible `if` statements. – Stephen Dec 22 '13 at 02:39
1

you should do:

if (room.exits.south) {// go that way}
else {print "you can't go that way!"}

that's it.

When "south" is undefined (or when it is zero or empty string or literal false), the predicate evaluates to false.

akhikhl
  • 2,552
  • 18
  • 23
  • is this different from saying room.exits[south], as Stephen suggested above? – drenl Dec 22 '13 at 02:06
  • Absolutely no difference in how it works. The difference is purely syntactical. – akhikhl Dec 22 '13 at 02:07
  • mmm... from my own experimentation, I think the difference is that the brackets will accept a variable. You cannot say, per Stephen's examine, room.exits.direction. However you could say room.exits[direction]. – drenl Dec 22 '13 at 02:40
  • Ah, yes, you are right. More on that: exits.south will look for "south" key within "exits" map. So, here "south" is a LITERAL. exits[direction] gets the value of "direction" variable (which must be defined elsewhere) and looks for it's value within "exits" map. Thousand times sorry. Sometimes even simple things require to stop and think carefully. – akhikhl Dec 22 '13 at 09:58