可能被你忽略的 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;
简单质朴,往往是最好的。


猜你喜欢
- 问题你想根据一组语法规则解析文本并执行命令,或者构造一个代表输入的抽象语法树。 如果语法非常简单,你可以不去使用一些框架,而是自己写这个解析
- for splitValue in set(dataset[:, featureIndex].tolist()):首先set是一个无序,无重
- 1.Django实现WebSocket在线聊天室1.1 安装pip install channels==2.3(saas) F:\Deskt
- 任务:基于线程池来操作MySQL,测试单台机器读写MySQL单表的效率。思路:创建一个大小合适的线程池,让每个线程分别连接到数据库并进行读取
- 以前写过一个刷校内网的人气的工具,Java的(以后再也不行Java程序了),里面用到了验证码识别,那段代码不是我自己写的:-) 校内的验证是
- 方法一: select `name` from mysql.proc where db = 'your_db_name' a
- 从概念上讲,大多数关系数据库系统都是类似的:它们都由一组数据库组成,且每个数据库都包含一组表。但是,所有的系统都有自己的管理数据的方法, M
- 前言在做接口自动化的时候,经常会遇到一些参数是需要加密的,比如密码参数。加密规则一般开发也不愿意告诉你,会直接给你一个jar包,让你调用ja
- 直接使用model2=model1会出现当更新model2时,model1的权重也会更新,这和自己的初始目的不同。经评论指出可以使用:mod
- 本文研究的主要是PyQt5打开文件对话框QFileDialog的代码示例,具体如下。单个文件打开 QFileDialog.getOpenFi
- 本文实例讲述了smarty模板引擎从配置文件中获取数据的方法。分享给大家供大家参考。具体如下:当某个变量值,不希望在程序中写死时,就可以把该
- jsp表达式方式: <center> <table border="1"> <% for
- 简述小编经常会遇到一些数据库编码不对得问题,好TM头疼,这里做一个记录,供大家参考。修改数据库字符集:ALTER DATABASE db_n
- python时间处理月份加减第三方模块 :python-dateutil安装方式:pip install python-dateutil实例
- 我们平时需要使用 Python 发送各类邮件,这个需求怎么来实现?答案其实很简单,smtplib 和 email 库可以帮忙实现这个需求。s
- 三元条件判断的3种实现方法C语言中有三元条件表达式,如 a>b?a:b,Python中没有三目运算符(?:),但Python有它自己的
- Git 恢复到之前版本1. 应用场景进行了错误提交,需要将代码回退至某个版本;或者需要检出某个版本的代码,再切换回最新版本。2. 解决方法2
- HTML5,被传为Flash 的杀手,是一种用于web 应用程序开发、具有变革意义的网络技术。HTML 5提供了一些新的元素和属性,其中有些
- 引言使用 python 绘制网络训练过程中的的 loss 曲线以及准确率变化曲线,这里的主要思想就时先把想要的损失值以及准确率值保存下来,保
- 相信很多人都跟小编一样不管是什么账号,如果很久不用就会忘记登录密码,像数据库SQL Server2008也一样有用户名和登录密码,下面小编就