欢迎光临

木子屋

标题: Javascript风格要素 Ⅱ

作者: dnawo

日期: 2008-02-29 04:40 PM

分类: 脚本语言

内容: 我们使用习惯用法可以使我们的意图更加的清晰和简洁。
使用==时，当心强制转换
考虑下面函数：
复制内容到剪贴板 程序代码function gw(f) {
if (d.w.sv.checked == true) {
zv = 'on';
} else {
zv = 'off';
}
procframe.location.replace("http://b.www.yahoo.com/module/wtr_tr.php?p=" +
escape(f.p.value) + "&sv=" + zv);
return false;
}
==运算符不应该被用着和true比较值，因为它要执行强制转换。如果我们想确定d.w.sv.checked是否是布尔值
true，我们必须用===运算符。如果我们仅在意一个值是真实存在的不是假的，最好不要用相等运算符。
例如，由于强制转换：1 == true是真，1 === true是假。==运算符隐藏了类型错误。
使用?:运算符选择两值之一
if语句通常被用来从两个值中选择一个。这应该是三元操作符?:最适合的。
复制内容到剪贴板 程序代码zv = d.w.sv.checked ? 'on' : 'off';
绝不使用隐含的全局变量
变量zv不是作为一个var或函数参数来声明的，所以它是一个隐式的全局变量。如果这个页面的另一个函数使用了同样名字的全局变量，则可能得到一个失败的结果。这样的臭虫（bug）是非常难以发现，却很容易避免。这个例子中，我们既可以声明zv为一个var，也可以发现它仅仅被使用过一次而整个去掉它。
复制内容到剪贴板 程序代码function gw(f) {
procframe.location.replace("http://b.www.yahoo.com/module/wtr_tr.php?p=" +
escape(f.p.value) + "&sv=" + d.w.sv.checked ? 'on' : 'off');
return false;
}
绝不使用?:运算符选择两种行为之一
我们常质疑那些返回一个常量的函数，但这有时是在浏览器环境下所必需的。
下面我们看一个不正确使用?:运算符的例子。它常被用于在两个任务间选择。
复制内容到剪贴板 程序代码function u(o, z) {
var em = o.id.substring(1);
var p = d.getElementById('e' + em);
if (p) {
(z == 0) ? p.style.backgroundColor = '#fff' :
p.style.backgroundColor = '#989898';
}
p = d.getElementById('e' + (em - 1));
if (p) {
(z == 0) ? p.style.backgroundColor = '#fff' :
p.style.backgroundColor = '#989898';
}
}
对z的判断是模糊不清的。z正好等于0时我们选择#fff颜色，那么，Z不等于时？如上所述似乎指明的是前者，但它实际上是后者。在这个例子中幸运的是，我们大概想要的就是后者，所以它不是技术上错误（这次）。但是在文体上只糟糕的。
我们可以用if代替?:，但碰巧的是这些值对应的是同一个左值(lvalue)，所以我们无需if就可以改正这个错误。
复制内容到剪贴板 程序代码function u(o, z) {
var em = o.id.substring(1),
p = d.getElementById('e' + em);
if (p) {
p.style.backgroundColor = z ? '#fff' : '#989898';
}
p = d.getElementById('e' + (em - 1));
if (p) {
p.style.backgroundColor = z ? '#fff' : '#989898';
}
}
使用||运算符指定一个默认值
事件处理程序依赖于浏览器。理想情况下，应用程序应该通过公共库隔绝对浏览器的依赖。当没有这样的库时，就会有些函数发生如下情况：
复制内容到剪贴板 程序代码function md(e) {
(window.event) ? ev = window.event : ev = e;
(ev.target) ? sr = ev.target : sr = ev.srcElement;
if (ev && sr && sr.id == "fp" || sr.id == "sb") st = 1;
if (sr.className.indexOf("pllist") < 0 && sr.className != "more" &&
sr.className != "plinkc" && sr.tagName != "scrollbar " &&
_toClose && _toCloseNorgie) {
d.getElementById(_toClose).innerHTML = "";
_toClose = "";
_toCloseNorgie.parentNode.className = '';
_toCloseNorgie = '';
}
}
一些浏览器把事件对象作为一个参数传给事件管理程序。微软选用把事件对象放入到一个全局的事件变量中。在Javascript中，全局变量是全局对象的成员。在浏览器中，全局对象始终包含一个window对象成员，其值是全局对象。当测试一个变量是否存在时，通过window访问全局变量是避免未定义变量错误的一种方法。无论如何，做这样的测试不应该是必要的。
我们能通过问它是否是另外一种，来代替首先判断是否是微软事件。
ev = e || event;我们用||(默认)运算符。如果e是真，我们将有它的值，但是如果e是假，则我们将用event。
在下一个语句，我们又用||运算符去确定sr是哪个值。
我们应该用var去声明ev和sr来避免全局冲突：
复制内容到剪贴板 程序代码function md(e) {
var ev = e || event,
sr = ev.target || ev.srcElement;
if (sr && (sr.id == 'fp' || sr.id == 'sb')) {
st = 1;
}
if (sr.className.indexOf('pllist') < 0 && sr.className != 'more' &&
sr.className != 'plinkc' && sr.tagName != 'scrollbar ' &&
_toClose && _toCloseNorgie) {
d.getElementById(_toClose).innerHTML = '';
_toClose = '';
_toCloseNorgie.parentNode.className = '';
_toCloseNorgie = '';
}
}
全局变量是魔鬼
下面我们看到另一个时间处理程序。正如你所料，它重复像前面一样破坏风格。
复制内容到剪贴板 程序代码function kd(e) {
(window.event) ? ev = window.event : ev = e;
(ev.target) ? el = ev.target : el = ev.srcElement;
if (ev && el) {
code = ev.keyCode;
id = el.id;
} else {
return;
}
ctn = lt.id.substring(1);
if (code == 13) {
return;
} else if ((code == 191 || code == 222) && id != 'fp') {
_ffs = 1;
gk = 0;
} else if ((code < 31 || code > 41) &&
(code < 16 || code > 18) && code != 9 && code != 8 ) {
gk = 1;
} else {
gk = 0;
}
if (!_ffs && (id == 'fp' || id == 'st')) {
if (code == 9) {
if (box.value == '' || (box.value != '' && (at == 1 || ev.shiftKey))) {
mt(ctn);
} else if (id == 'st' && box.value != '' && at == 0) {
at = 1;
mt(ctn);
}
} else if (id == 'fp' && gk == 0 && (box.value == '' && st == 0)
&& !ev.shiftKey && !ev.ctrlKey && !ev.altKey) {
d.getElementById('mk').focus();
d.getElementById('mk').blur();
} else if (gk == 1) {
at = 0;
}
} else if ((id == 'mk2' && box.value != '' && ev.shiftKey && code == 9) ||
(id == 'm6' && !ev.shiftKey && code == 9)){
d.getElementById('mk').focus();
} else if (!_ffs && gk == 1 && el.type != 'text' && !ev.ctrlKey && !ev.altKey){
box.value = '';
box.focus();
}
}
function mt(ctn) {
if ((ev && !ev.ctrlKey && !ev.altKey) || !ev) {
if (ev.shiftKey){
nextTab = parseInt(ctn) - 1;
} else {
nextTab = parseInt(ctn) + 1;
}
if (nextTab == 0) {
d.getElementById('mk').focus();
} else if (nextTab < 8 ) {
t(d.getElementById('v' + nextTab));
} else {
return;
}
}
}
有意思的是它有一个同伴函数mt，它仅被kd调用。mt被传给一个参数ctn，但kd和mt之间的通讯大部分是通过全局变量。
使用内部函数避免全局变量
我们可以通过增加传递给mt的参数数量来除掉所有的全局变量。但代替方案，我们将使mt变成kd的内部函数。作为一个内部函数，mt能访问kd的所有变量。
复制内容到剪贴板 程序代码unction kd(e) {
var ev = e || event,
el = ev.target || ev.srcElement,
cnt,
code = ev.keyCode,
gk,
id = el.id,
ctn = lt.id.substring(1);
function mt() {
var nextTab;
if (!ev.ctrlKey && !ev.altKey) {
nextTab = parseInt(ctn) + ev.shiftKey ? -1 : 1;
if (!nextTab) {
d.getElementById('mk').focus();
} else if (nextTab < 8 ) {
t(d.getElementById('v' + nextTab));
}
}
}
if (code == 13) {
return;
} else if ((code == 191 || code == 222) && id != 'fp') {
_ffs = 1;
gk = 0;
} else if ((code < 31 || code > 41) &&
(code < 16 || code > 18) && code != 9 && code != 8 ) {
gk = 1;
} else {
gk = 0;
}
if (!_ffs && (id == 'fp' || id == 'st')) {
if (code == 9) {
if (box.value == '' ||
(box.value != '' && (at == 1 || ev.shiftKey))) {
mt();
} else if (id == 'st' && box.value != '' && at == 0) {
at = 1;
mt();
}
} else if (id == 'fp' && gk == 0 && (box.value == '' && st == 0) &&
!ev.shiftKey && !ev.ctrlKey && !ev.altKey) {
d.getElementById('mk').focus();
d.getElementById('mk').blur();
} else if (gk == 1) {
at = 0;
}
} else if ((id == 'mk2' && box.value != '' && ev.shiftKey && code == 9) ||
(id == 'm6' && !ev.shiftKey && code == 9)){
d.getElementById('mk').focus();
} else if (!_ffs && gk == 1 && el.type != 'text' && !ev.ctrlKey &&
!ev.altKey) {
box.value = '';
box.focus();
}
}
在函数kd中，从两个地方调用函数mt。通过使它成为一个内部函数，我们能有效的减少kd所用到的全局变量的数目，这将降低了干扰其他组件的可能性。kd依旧是一个烂摊子，但它现在不是一无是处的烂摊子。
原文：Douglas Crockford 的 The Elements of JavaScript Style Part Two: Idioms

+ 查看当前日志评论 (0)

登录

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.672 ms

返回

标题: Javascript风格要素 Ⅱ

你没有权限发表评论

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.672 ms

返回

暂无评论

返回

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.703 ms

返回