JavaScript对象字面量中如何测试键名是否存在

4
在我正在制作的文字冒险游戏中,我的房间对象字面量看起来像这样:
room : {
  // some info,
  exits : {
    north : -1,
    east : "house",
    south : "forest",
    west : -1
  }
}

在我的移动函数中,它说:

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

现在我想通过测试对象中是否存在相关方向的键来节省空间。因此,字面量将变为:

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

...我的if语句应该怎么写?在对象中确定给定的键名是否存在的“正确”方法是什么?


这些都看起来是很好的答案。这里有一个相关的问题。非键值返回什么?例如:在上面的例子中,var foo = room.exits[bar] ... foo是null吗?还是undefined? - drenl
如果bar不存在,room.exits[bar]将返回undefined。而'bar' in room.exits则会返回false - p.s.w.g
可以给我指一下一个参考资料,解释一下 null、undefined 和 falsey(在这个上下文中适用),让新手也能理解的? - drenl
请参阅以下链接以了解有关JavaScript中null和undefined之间的区别的内容:https://dev59.com/aW445IYBdhLWcg3wBVzz 和 http://www.sitepoint.com/javascript-truthy-falsy/ - p.s.w.g
非常棒。感谢大家的讨论! - drenl
3个回答

6
你可以使用 in 运算符
if (direction in room.exits) {
    // go that way
} else { 
    console.log("you can't go that way!");
}

我给你点赞,因为我没有想到使用这个方法,但我发现了一些有趣的信息(发布在我的答案中),应该考虑到。 - Stephen
@Stephen,非常感谢你的有趣观察。如果 OP 需要执行数百万次检查,那么这将是一个大问题。然而,在我看来,这似乎不是应用程序中特别关键的性能部分。两种解决方案都是完全有效的。 - p.s.w.g
非常正确 - 但是希望这样的信息能够被储存起来,以备不时之需 :) - Stephen

3

如果绝对不会是null、空字符串、零或任何其他“假值”JS值,那么您可以直接执行以下操作:

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

我也对p.s.w.g发布的“in”运算符进行了速度测试,因为我从未想过使用它。如果你在任何时候运行循环,请考虑一下我发现的一些有趣结果。

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

似乎“in”运算符在IE和Chrome上明显较慢,但在Firefox上快近一倍。


嗯,这是与akhikhl的答案相反,还是只是另一种表达方式? - drenl
嗯,它们基本上是一样的——不同之处在于我的“方向”是一个变量,而akhikhl的代码中则被设置了。我敢肯定我们几乎同时保存了相似的代码。 - Stephen
是的,我只是指使用句点和方括号。暂且假设他正在使用一个变量。 - drenl
在性能方面实际上是有差别的。使用变量属性比执行 room.exists.something 更昂贵,但是(就像 p.s.w.g 的答案一样),与最少四个不同的可能的 if 语句相比,它可以提高可读性。 - Stephen

1
你应该做的是:

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

就是这样。

当“south”未定义(或为零、空字符串或字面上的false)时,谓词计算结果为false。


这与Stephen上面建议的room.exits[south]有什么不同吗? - drenl
它的工作方式完全相同,区别纯粹是语法上的。 - akhikhl
从我的实验来看,我认为区别在于括号可以接受一个变量。你不能像Stephen的检查一样说room.exits.direction。但是你可以说room.exits[direction]。 - drenl
啊,是的,你说得对。更进一步解释:exits.south 将在“exits”映射中查找“south”键。因此,在这里,“south”是一个字面量。exits[direction] 获取“direction”变量的值(该变量必须在其他地方定义),并在“exits”映射中查找其值。千万次抱歉。有时即使是简单的事情也需要停下来仔细思考。 - akhikhl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接