【问题标题】:What are the top JavaScript pitfalls? [closed]JavaScript 的主要陷阱是什么? [关闭]
【发布时间】:2010-05-01 12:45:00
【问题描述】:

我打算做一个关于 JavaScript 的介绍性演讲,在准备过程中,我想知道新手最容易陷入的陷阱是什么。

我知道在完全理解闭包之前我已经遇到了一些问题,但是 JavaScript 中的许多奇怪行为我已经不再考虑了......

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

【问题讨论】:

标签: javascript debugging


【解决方案1】:

Boolean type conversion.

''        ==   '0'           //false
0         ==   ''            //true
0         ==   '0'           //true
false     ==   'false'       //false
false     ==   '0'           //true
false     ==   undefined     //false
false     ==   null          //false
null      ==   undefined     //true
" \t\r\n" ==   0             //true

还有nullundefined的区别。如上表所示,将nullundefined== 进行比较返回true,但与=== 进行比较则返回false。一旦您了解undefined 与具有null 值的变量非常不同,并且持有 undefined 的东西与某物存在 未定义。

【讨论】:

    【解决方案2】:

    不要不小心在对象定义字面量中留下逗号,否则 IE 会失败,而且您直到很久以后才会注意到,因为您从不使用 IE 进行开发,到那时它可能会搞不清楚发生了什么。

    var foo = { 
        bar: "bar", 
        baz: "baz", 
    };
    

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

    【讨论】:

    • +1 这个很有辨识度。在数组中,IE 不会因为抛出一些语法错误而直接失败,但是当您尝试使用数组时会失败,因为添加的逗号使 IE 认为数组中还有一个元素,其值为 undefined,而不是实际存在.因此,如果由于某种原因数组中的最后一个元素是 undefined 而出现错误:它是一个逗号。
    • +1 很棒的评论,这是一个非常讨厌的陷阱。
    【解决方案3】:

    诚然,我过去曾犯过其中的一些罪行,为了您的开心,这是粗体字:

    • 不知道 eval
      eval("obj."+prop);
    • 的不正确(以及极少数正确)用法
    • 使用with 语句
    • 使用 parseInt(str, base) 而不指定 base 参数。
    • 在定时器/回调函数中使用this
    • 在计时器中使用类似 eval 的表达式
      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 语句来检查变量。
    • 愚蠢地试图通过阻止在您的页面上单击鼠标右键来停止“查看源代码”(我还年轻*sobs*!)
    • 使用{ 0: "Foo", 1:"Bar", 2:"Foobar" } 代替[ "Foo", "Bar", "Foobar" ]
    • 在用户输入中使用parseInt()
      parseInt("1,000") // -> 1, wrong!
      +"1,000" // -> NaN, correct!

    一些已经提到的:

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

    睡觉后可能会想更多:-)

    【讨论】:

    • 为什么不应该在回调中使用this
    • @Lèse:因为回调函数,尤其是与计时器一起使用的回调函数,通常没有上下文。
    • @Andy E:如果你要为事件监听器分配回调呢?
    • @Lèse:当然,这些是例外,尽管它们更多地被称为事件侦听器或事件处理程序而不是回调函数(即使它们是回调函数)。混淆通常源于在事件侦听器函数中使用this,很多人认为this对于在同一范围内定义的函数保持不变。
    • 啊,谢谢你的澄清。
    【解决方案4】:
    • 忘记用var 声明变量
    • 误解(或不理解)变量范围和闭包
    • 试图解决框架团队已经解决的令人讨厌的兼容性问题

    【讨论】:

    • 绝对是框架。无论如何,在使用之前应该有人了解 JS。但他们应该知道他们在那里。
    • 是的,框架可能是一个大陷阱。这个网站充斥着新手试图用 jQuery 做一些特定事情的问题。 jQuery 有一个功能几乎可以完成任务,或者完成一些任务,但它太自动化了,无法更普遍地使用。
    【解决方案5】:

    + 连接字符串:

    var a = '2';
    var b = 3;
    
    a * b #  6
    a - b # -1
    a + b #  23
    

    【讨论】:

    • 我同意你的看法。很多次我不得不写类似a * 1 + b * 1 的东西来完成这个技巧或将它们解析为int。这太荒谬了。
    • 这也可以+(a) + b #5
    • @Fuex - +a+ +b 更短。
    【解决方案6】:

    JavaScript 字符串不是字节字符串,甚至也不是 Unicode 字符串。它们是 UTF-16 字符串。大多数字符,包括国际字符,都是 JavaScript 字符串中的单个元素。但有些字符(包括大多数表情符号)不在基本多语言平面范围内,因此在 JavaScript 字符串中显示为两个元素。

    例子:

    > "♫".length
    1
    > "?".length
    2
    > "?".charAt(0)
    "\uD800"
    > "?".charAt(1)
    "\uDF08"
    > "?" === "\uD800\uDF08"
    true
    

    【讨论】:

    • 只是吹毛求疵:使用 UTF-16 字符串并没有什么问题,问题在于抽象的泄漏(如 Javascript、.NET、Java 等) 一个理智的文本 API 支持的示例通过 UTF-16 是 Haskell 的 Data.Text:(T.length $ T.pack "?") == 1 返回 True
    • UTF-16 是一种编码 unicode 的方法。所以是的,它们是 unicode 字符串。
    • @berdario: 咳嗽 utf8everywhere.org 咳嗽 ^^
    • 我拒绝了将“Unicode 字符串”更改为“UTF-8 字符串”的编辑。我在这里要指出的是,JavaScript 字符串不是 Unicode 代码点序列。每个“数组元素”都是一个 UTF-16 代码点,这意味着代理对表示为两个“字符”而不是一个。
    【解决方案7】:

    我看到初学者最大的困难是理解执行上下文(即,无论何时何地遇到“this”的含义)和继承的原型系统。

    【讨论】:

      【解决方案8】:
      • Closures - 也称为 lambda 函数 - 注意内存泄漏。
      • 浏览器差异,必须在 Internet Explorer 和至少一个其他浏览器中进行测试。通常应避免仅在某些浏览器中工作或在不同浏览器中工作方式不同的功能。如果这不可能,浏览器特定的分支最好检测浏览器功能而不是浏览器版本。这增加了代码在未来的浏览器和未经测试的浏览器中工作的机会。
      • 过于沉迷于jQueryAjax 框架抽象,并且对下划线的JavaScript 不够了解,无法知道如何解决框架问题。
      • 不知道 JavaScript 在某种程度上可以用来编写 OOP 代码。事实上,它可以为您提供一个非常基本的带有对象的 OOP 框架。
      • 区分大小写(如果您是VB.NET 开发人员)
      • IP 保护 - 知道您可以混淆 JavaScript,但您发布的源代码很容易被窃取和逆向工程。根据您正在编写的客户端应用程序的复杂性,这甚至可能不是问题。

      我想不出更多了,但我希望这会有所帮助。

      【讨论】:

      • 浏览器检测是邪恶的。您应该使用特征检测,而不是浏览器检测。
      • @el.pescado:+1,但公平地说,有时您需要检测行为,这不像检测特征和对象那么容易。
      • “闭包 - 也称为 lambda 函数...”。不正确 - 闭包可以是 lambda,但不一定是(它们也可以是命名函数)。
      • @el.pescado:浏览器检测并不邪恶,它只是无效且容易出错。
      • 解决有关浏览器与功能检测的问题:这并不难做到。 jQuery 为处理这个问题提供了很好的支持 (api.jquery.com/jQuery.support)。如果您不想使用 jQuery,我仍然建议您查看 jQuery.support 源代码,因为它很容易根据需要自行实现。 (github.com/jquery/jquery/blob/master/src/support.js)
      【解决方案9】:
      • 使用window.onload = init(); 代替window.onload = init;
      • 布尔等价(如前所述)
      • 循环内的闭包。
      • 使用for in 循环变体对数组进行迭代。
      • 不使用;,因为它是“可选的”。
      • this(只是...一般来说:))
      • 不使用var
      • 知道obj.ref === obj["ref"]

      【讨论】:

        【解决方案10】:
        • 创建不使用 JavaScript 的网站
        • 将 JavaScript 用于应该在服务器端完成的事情
        • 为不需要框架的简单任务使用框架

        【讨论】:

          【解决方案11】:

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

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

          var Foo() = function ()
          {
              this.batz = '...';
          };
          Foo.prototype = new Bar();
          Foo.prototype.constructor = Foo;
          

          如果您忘记了最少的一行,new Foo() 将实际执行 Bar()

          原型设计的另一个缺陷是迭代对象/数组而不过滤掉原型的成员:

          for (var i in obj) {
              if (obj.hasOwnProperty(i)) {
                  //stuff...
              }
          }
          

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

          【讨论】:

            【解决方案12】:

            不是一个真正的编码陷阱,而是一个普遍的想法:
            不要相信你的 JavaScript 正在做的事情,它可能已被关闭甚至 monkey patched。这意味着永远不要依赖客户端验证。从来没有。

            【讨论】:

              【解决方案13】:
              typeof null is object
              
              
              >>> var i = 1 + undefined; i;
              NaN
              >>> var i = 1 + null; i;
              1
              

              【讨论】:

                猜你喜欢
                • 2013-01-18
                • 2011-12-13
                • 2010-11-16
                • 2011-02-26
                • 1970-01-01
                • 1970-01-01
                • 2010-12-19
                • 2011-02-22
                • 1970-01-01
                相关资源
                最近更新 更多