可能被你忽略的 JavaScript 代码陷阱

作者:lifesinger 来源:岁月如歌 时间:2009-12-26 18:16:00 


下面这段代码,你知道有哪些错误吗:

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 || documentname = 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 = 2var 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, 再举一例(和本文主题关系不明显,但的确又有关系,交给你去思考啰):

var isBoy = true;isBoy = typeof isGirl !== "undefined" ? !isGirl : true;

或者来个耍酷的代码:

var isBoy = true;(typeof isGirl !== "undefined") && (isBoy =  !isGirl);

然而,以上两种写法,无论从代码长度还是性能上讲,都不如更直白的写法:

var isBoy = true;if(typeof isGirl !== "undefined") isBoy =  !isGirl;

简单质朴,往往是最好的。

标签:代码,陷阱,JavaScript
0
投稿

猜你喜欢

  • 基于python3实现socket文件传输和校验

    2023-06-30 08:49:57
  • MySQL的加密解密的几种方式(小结)

    2024-01-17 06:25:22
  • Python自动生成代码 使用tkinter图形化操作并生成代码框架

    2021-04-26 08:47:30
  • 一文搞懂Python中Pandas数据合并

    2023-03-21 13:28:56
  • Python IDLE清空窗口的实例

    2023-11-22 17:59:23
  • 使用postman操作ElasticSearch的方法

    2023-04-22 20:58:14
  • pyspark创建DataFrame的几种方法

    2023-01-09 01:30:53
  • 在 Python 中利用Pool 进行多处理

    2022-03-07 13:10:36
  • tensorflow 用矩阵运算替换for循环 用tf.tile而不写for的方法

    2021-08-11 11:43:55
  • 利用索引提高SQL Server数据处理的效率

    2009-01-08 15:32:00
  • JS+CSS实现闪烁字体效果代码

    2024-04-18 09:31:04
  • Django 博客实现简单的全文搜索的示例代码

    2023-12-07 10:09:19
  • Python3爬虫爬取英雄联盟高清桌面壁纸功能示例【基于Scrapy框架】

    2023-03-07 19:19:59
  • Python解析器Cpython的GIL解释器锁工作机制

    2021-07-11 18:15:10
  • python Django的显示个人信息详解

    2021-10-09 15:47:14
  • Python动态演示旋转矩阵的作用详解

    2022-08-21 02:35:15
  • JSP学生信息管理系统

    2024-03-20 22:28:27
  • SQL Serve数据库到DB2连接服务器的实现过程全解

    2010-08-31 15:06:00
  • 一文教你利用Python画花样图

    2023-09-01 20:26:42
  • Python操作MongoDB数据库PyMongo库使用方法

    2023-03-16 00:13:14
  • asp之家 网络编程 m.aspxhome.com