可能被你忽略的 JavaScript 代码陷阱
下面这段代码,你知道有哪些错误吗:
以下是代码片段: var g_bar = "bar"; function foo(container, config) { var container = container || document, name = config.name || "无名氏", isLive = config.isLive || true; var g_bar = g_bar || ""; if(g_foo) { /* your code */ } } foo(document, {isLive: false}); |
请仔细思考后再往下阅读。
―- 帮助你思考的刷屏线 开始 ―-
―- 帮助你思考的刷屏线 结束 ―-
1. isLive = config.isLive || true
, 当传入的值有可能就是0, undefined, null, false, "", NaN
这六个 falsy 值时,用 || 来设定默认值不妥当。更保险的做法是:
以下是代码片段: isLive = "isLive" in config ? config.isLive : true; |
如果是独立变量,可以采用:
以下是代码片段: someVar = typeof someVar !== "undefined" ? someVar : defaultValue; |
注意:大部分情况下,用 || 已经够用,比如:
以下是代码片段: container = container || document name = config.name || "无名氏" |
一切皆权衡。
2. var g_bar = g_bar || ""
, 原意是取全局变量 g_bar 的值给内部变量 g_bar, 默认为空字符串。然而,实际情况等价为:
以下是代码片段: var g_bar; g_bar = g_bar || ""; |
很明显,|| 号左边的 g_bar 也是内部变量,并且为 undefined, 因此var g_bar = g_bar || ""
实际上是var g_bar = ""
, 没有满足代码的原始意图。
思考:代码中的var container = container || document
有无问题?为什么?
3. if(g_foo) { /* code */ }
, 这段代码在执行时会报错。我们都知道在 JS 里,变量不定义就可以用。但一定要清楚,未定义的变量,仅仅是可写,但不可读。比如:
以下是代码片段: g_foo = 2; // 等价 window.g_foo = 2 var t = g_foo2; // 不等价为 var t = window.g_foo2, 会报错 |
具体原因可以参见 JavaScript 运行机制浅探:
未定义变量意味着在 scriptObject 的变量表中找不到,JS 引擎会沿着 scriptObject 的 upvalue 往上寻找,如果都没找到,对于写操作 i = 1; 最后就会等价为 window.i = 1; 给 window 对象新增了一个属性。对于读操作,如果一直追溯到全局执行环境的 scriptObject 上都找不到,就会产生运行期错误。
因此严谨的写法是:
以下是代码片段: if(window.g_foo) { /* your code */ } |
不要小看这些细微之处,有时会让人抓狂的。但这些细微之处又很容易被忽略或滥用。比如 YUI 2.8r4 里,有一个遗传了很久的 bug:
以下是代码片段: var NOTHING = []; // .... later: function(when, o, fn, data, periodic) { when = when || 0; o = o || {}; var m = fn, d = data, f, r; // ... if (d && !L.isArray(d)) { d = [data]; } f = function() { m.apply(o, d || NOTHING); }; // ... } |
当你的调用代码类似Lang.later(delay[0], o, "show", index)
时,如果 index 不幸是 base-0 的,那么取 0 时,m.apply(o, d || NOTHING)
会让你得到“惊喜”。更妥的做法是类似 YUI3 中的修正:
以下是代码片段: // ... if (!L.isArray(d)) { d = [data]; }? f = function() { m.apply(o, d); }; //... |
对于 || 和 && 的用法,很多 JS 书籍(无论中外),都用来片面强调 JS 的灵活性,包括 Douglas 的《JavaScript The Good Parts》中也存在误导。
最后,有感于 NCZ 今天写的 Writing Maintainable Code, 再举一例(和本文主题关系不明显,但的确又有关系,交给你去思考
建议继续学习:
- Java陷阱(2010版) (阅读:3312)
- JavaScript性能陷阱 (阅读:3161)
- PHP数据类型隐性转换的陷阱 (阅读:3011)
- 移动互联网系统架构十大陷阱 (阅读:2896)
- 类型转换-无处不在的陷阱 (阅读:2318)
- JavaScript 中的陷阱 (阅读:1892)
- cPickle序列化自定义类实例时的陷阱 (阅读:1742)
- 情景反射陷阱 (阅读:1720)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:lifesinger 来源: 岁月如歌
- 标签: 陷阱
- 发布时间:2009-12-17 09:16:28
- [69] Twitter/微博客的学习摘要
- [67] IOS安全–浅谈关于IOS加固的几种方法
- [65] android 开发入门
- [65] 如何拿下简短的域名
- [63] find命令的一点注意事项
- [62] Go Reflect 性能
- [61] 流程管理与用户研究
- [60] Oracle MTS模式下 进程地址与会话信
- [59] 图书馆的世界纪录
- [57] 读书笔记-壹百度:百度十年千倍的29条法则