关于调试:最重要的JavaScript陷阱是什么?

What are the top JavaScript pitfalls?

我正打算做一个关于javascript的介绍演讲,在准备过程中,我想知道新手会遇到什么最大的陷阱。

我知道在我完全理解闭包之前我已经有了一些理解,但是JavaScript中的许多奇怪行为已经不再是我所想的了…

那么,你应该向新手明确指出哪些陷阱呢?


布尔类型转换。

1
2
3
4
5
6
7
8
9
10
11
''        ==   '0'           //false
0         ==   ''            //true
0         ==   '0'           //true
false     ==   'false'       //false
false     ==   '0'           //true
false     ==   undefined     //false
false     ==   null          //false
null      ==   undefined     //true
" \t

"
==   0             //true

以及nullundefined之间的区别。如上表所示,比较nullundefined==返回真,而===返回假。一旦你了解到undefined与具有null值的变量非常不同,并且具有undefined值的某个变量与未定义的某个变量不同,这种行为就有意义了。


不要在对象定义文本中意外地留下一个尾随逗号,否则IE将失败,并且直到很晚才会注意到,因为您从未使用IE进行开发,到那时,它可能会搞不清发生了什么。

1
2
3
4
var foo = {
    bar:"bar",
    baz:"baz",
};

注:朱利安评论:在数组中,ie不会直接通过抛出某些语法错误而失败,但在尝试使用数组时会失败,因为添加的逗号使ie认为数组中还有一个元素,其值为undefined,而不是实际存在的元素。因此,如果由于某种原因出现错误,数组中的最后一个元素是undefined:它是逗号。


诚然,我过去曾犯过一些这样的错误,为了取悦你,我大胆地说:

  • 不知道eval
    1
    eval("obj."+prop);

    的错误(以及极少的正确)用法

  • 使用with语句
  • 使用parseInt(str, base)而不指定base参数。
  • 在定时器/回调函数中使用this
  • 在计时器中使用类似eval的表达式
    1
    setTimeout("someFunc(myScopedVarWhoops)");

    代码>

  • 认为jquery是您正在编码的语言的名称
  • 使用框架执行简单的javascript任务——$(1).plus(1)有人吗?;-)
  • 在不增加或调整条件变量的情况下使用continue
  • 用变量填充全局命名空间
  • for语句中或之前忘记varfor (i=0;i<10;i++)
  • 使用一个模糊器,让它在你的代码上疯狂运行
  • 不是一个真正的陷阱,而是毫无意义的-return condition ? true : false;而不是return condition;
  • 不评论代码,适用于所有语言。
  • 使用try...catch...finally语句捕获错误,而不是使用if语句检查变量。
  • 愚蠢地试图通过阻止鼠标右键点击你的页面来停止"查看源代码"(我还年轻*呜咽*!)
  • { 0:"Foo", 1:"Bar", 2:"Foobar" }代替["Foo","Bar","Foobar" ]
  • 用户输入时使用parseInt()
    1
    2
    parseInt("1,000") // -> 1, wrong!
    +"1,000" // -> NaN, correct!

    代码>

一些人已经提到:

  • 尽可能不使用严格相等(===运算符)
  • 将事件处理程序设置为函数的返回值,而不是对所述函数的引用
  • 未正确使用;终止语句
  • 在阵列上使用for...in循环

可能在我睡了之后会想到更多的事情——)


  • 忘记用var声明变量
  • 误解(或不理解)变量范围和闭包
  • 试图解决框架团队已经解决的讨厌的兼容性问题


+连接字符串:

1
2
3
4
5
6
var a = '2';
var b = 3;

a * b #  6
a - b # -1
a + b #  23


javascript字符串不是字节字符串,甚至不是Unicode字符串。它们是UTF-16字符串。

例子:

1
2
3
4
5
6
7
8
9
10
>"?".length
1
>"??".length
2
>"??".charAt(0)
"\uD800"
>"??".charAt(1)
"\uDF08"
>"??" ==="\uD800\uDF08"
true

如果上面的内容看起来像垃圾,那么就怪你的浏览器有错误的unicode处理(或者你的字体没有"旧斜体字母"字符)。


对于初学者来说,我看到的最大困难是理解执行上下文(即,无论何时何地遇到"这"意味着什么)和继承原型系统。


  • 闭包——也叫lambda函数——注意内存泄漏。
  • 浏览器差异,必须在Internet Explorer和至少一个其他浏览器中进行测试。通常应避免只在某些浏览器中工作或在不同浏览器中工作不同的函数。如果这是不可能的,那么特定于浏览器的分支最好检测浏览器功能,而不是浏览器版本。这增加了代码在未来浏览器和未经测试的浏览器中工作的机会。
  • 过于沉迷于jquery或ajax框架抽象,并且不太了解底层的javascript,不知道如何解决框架问题。
  • 不知道javascript在某种程度上可以用来编写OOP代码。实际上,它可以为您提供一个非常基本的对象OOP框架。
  • 区分大小写(如果您是vb.net开发人员)
  • IP保护——知道你可以混淆javascript,但是你输出的源代码很容易被窃取和逆向工程。根据您正在编写的客户端应用程序的复杂性,这甚至可能不是一个问题。

我再也想不起来了,但我希望这有帮助。


  • 创建不使用javascript的网站
  • 在服务器端使用JavaScript
  • 为不需要的简单任务使用框架

  • window.onload = init();代替window.onload = init;
  • 布尔等价(如前所述)
  • 在循环中关闭。
  • 使用for in循环变量迭代数组。
  • 不使用;,因为它是"可选的"。
  • this(只是…一般情况下)
  • 不使用var
  • 知道obj.ref === obj["ref"]

原型设计的整个概念需要一段时间才能完全理解,但以下是一些常见的陷阱:

分配原型对象后忘记重置构造函数属性:

1
2
3
4
5
6
var Foo() = function ()
{
    this.batz = '...';
};
Foo.prototype = new Bar();
Foo.prototype.constructor = Foo;

如果你忘了最不重要的一行,new Foo()实际上会执行Bar()

原型化的另一个陷阱是在不过滤原型成员的情况下对对象/数组进行迭代:

1
2
3
4
5
for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
        //stuff...
    }
}

额外的条件将跳过从obj原型继承的任何成员。


不是真正的编码陷阱,而是更普遍的想法:不要相信你的javascript正在做的事情,它可能已经被关闭,甚至是猴子补丁。这意味着永远不要依赖客户端验证。从未。


1
2
3
4
5
6
7
typeof null is object


>>> var i = 1 + undefined; i;
NaN
>>> var i = 1 + null; i;
1