资讯专栏INFORMATION COLUMN

怪异的JavaScript系列(二)

YacaToy / 1801人阅读

摘要:函数不是函数这是一个低版本的,,或则。对应的进制数为。因此最安全的方法是调用的时候指定进制。它会将字符串形式的整数转换为,非字符串的,,和也会被转换。对于不能转换的值,返回。而浏览器主要指系列,其实已经没有必要支持这个特性了。

译者按: JavaScript有很多坑,经常一不小心就要写bug。

原文: What the f*ck JavaScript?

译者: Fundebug

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

JavaScript是一门伟大的语言,它拥有非常简洁的语法,庞大的生态系统,以及最重要的:有一个伟大的社区支撑着。同时,我们也知道JavaScript是一个充满技巧性的语言。有些坑足以让我们崩溃,也有些奇淫技巧让我们觉得很有趣。本文的思想源自于Brian Leroux在dotJS2012上的演讲“WTFJS” at dotJS 2012。

我收集这些例子的主要目的是将它们整理并清楚理解它们的原理。从中学到很多以前不懂的知识是一件很有趣的事情。如果你是初学者,你可以通过学习这些笔记深入理解JavaScript;如果你是一个专业的开发者,那么可以将这些笔记作为一个不错的引用资料。不管怎样,只要读下去,你就会学到新东西的。

函数不是函数?

</>复制代码

  1. ⚠️ 这是一个低版本的bug,V8(<=5.5),或则Node.js(<=7)。

</>复制代码

  1. // Declare a class which extends null
  2. class Foo extends null {}
  3. // -> [Function: Foo]
  4. new Foo instanceof null
  5. // > TypeError: function is not a function
  6. // > at … … …

备注:经测试高版本(Node.js, v8.1.1)不会出现这个bug。如果你还没升级到高版本,不妨试一下看看?

数组相加

如果我们将两个数组相加,结果会怎样?

</>复制代码

  1. [1, 2, 3] + [4, 5, 6] // -> "1,2,34,5,6"

实际上是做了拼接操作,我们来一步一步解释:

</>复制代码

  1. [1, 2, 3] + [4, 5, 6]
  2. // 调用 toString()
  3. [1, 2, 3].toString() + [4, 5, 6].toString()
  4. // 字符串拼接
  5. "1,2,3" + "4,5,6"
  6. // ->
  7. "1,2,34,5,6"
数组中分号的去除

我们创建一个4个空元素的数组。结果呢,该数组实际上只有3个元素,因为最后一个分号被去掉了。

</>复制代码

  1. let a = [,,,]
  2. a.length // -> 3
  3. a.toString() // -> ",,"

</>复制代码

  1. 末尾分号(Trailing commas)(又叫做final commas)在添加新元素、参数或则属性时候很有用。如果你想增加一个新的属性,并且前一行末尾有使用分号,你可以直接在新的一行添加而不用修改前一行。这可以让版本控制的diff操作更加清晰,代码更少出问题。- Trailing commas at MDN
数组相等匹配非常恐怖

请看:

</>复制代码

  1. [] == "" // -> true
  2. [] == 0 // -> true
  3. [""] == "" // -> true
  4. [0] == 0 // -> true
  5. [0] == "" // -> false
  6. [""] == 0 // -> true
  7. [null] == "" // true
  8. [null] == 0 // true
  9. [undefined] == "" // true
  10. [undefined] == 0 // true
  11. [[]] == 0 // true
  12. [[]] == "" // true
  13. [[[[[[]]]]]] == "" // true
  14. [[[[[[]]]]]] == 0 // true
  15. [[[[[[ null ]]]]]] == 0 // true
  16. [[[[[[ null ]]]]]] == "" // true
  17. [[[[[[ undefined ]]]]]] == 0 // true
  18. [[[[[[ undefined ]]]]]] == "" // true

具体请参考7.2.13 Abstract Equality Comparison

undefined和Number

如果不给Number构造函数传入任何参数,那么返回0。如果传入undefined作为参数,会返回NaN。

</>复制代码

  1. Number() // -> 0
  2. Number(undefined) // -> NaN

根据规范:

如果没有参数传入,那么n=0;

否则,n= ToNumber(value);

如果value为undefined,那么ToNumnber(undefined)为NaN。

参考:

20.1.1 The Number Constructor

7.1.3 ToNumber(argument)

JavaScript坑很多,赶紧使用fundebug扶一扶!

parseInt也不是个好东西

parseInt因为它奇怪的行为而出名:

</>复制代码

  1. parseInt("f*ck"); // -> NaN
  2. parseInt("f*ck", 16); // -> 15

这是因为parseInt一个字符一个字符去分析,知道遇到无法处理的字符。f对应的16进制数为15。

Infinity可以转换为对应的数字:

</>复制代码

  1. //
  2. parseInt("Infinity", 10) // -> NaN
  3. // ...
  4. parseInt("Infinity", 18) // -> NaN...
  5. parseInt("Infinity", 19) // -> 18
  6. // ...
  7. parseInt("Infinity", 23) // -> 18...
  8. parseInt("Infinity", 24) // -> 151176378
  9. // ...
  10. parseInt("Infinity", 29) // -> 385849803
  11. parseInt("Infinity", 30) // -> 13693557269
  12. // ...
  13. parseInt("Infinity", 34) // -> 28872273981
  14. parseInt("Infinity", 35) // -> 1201203301724
  15. parseInt("Infinity", 36) // -> 1461559270678...
  16. parseInt("Infinity", 37) // -> NaN

小心参数为null的情况:

</>复制代码

  1. parseInt(null, 24) // -> 23

</>复制代码

  1. 首先,null被翻译为字符串"null""n"24进制中对于23。-- 更多请参考 “parseInt(null, 24) === 23… wait, what?” at StackOverflow。

</>复制代码

  1. parseInt("n", 24) // -> 23

不要忘记了8进制:

</>复制代码

  1. parseInt("06"); // 6
  2. parseInt("08"); // 8 if support ECMAScript 5
  3. parseInt("08"); // 0 if not support ECMAScript 5

如果输入的字符串以0开始,那么为8进制或则10进制。到底是哪一个,要看实现。如果是ECMAScript5,则为10进制。但并不是所有浏览器都支持。因此最安全的方法是调用parseInt的时候指定进制。

parseInt总是将输入转换为字符串。

</>复制代码

  1. parseInt({ toString: () => 2, valueOf: () => 1 }) // -> 2
  2. Number({ toString: () => 2, valueOf: () => 1 }) // -> 1
true和false的数学运算

</>复制代码

  1. true + true // -> 2
  2. (true + true) * (true + true) - true // -> 3

我们把true转换为Number来看看就明白了:

</>复制代码

  1. Number(true) // -> 1

一元加号运算会尝试将参数转换为number。它会将字符串形式的整数转换为float,非字符串的true,false,和null也会被转换。对于不能转换的值,返回NaN。因此,我们有了一个更加简单的转换方法:

</>复制代码

  1. +true // -> 1

当你使用加法或则乘法的时候,ToNumber函数会被调用。根据定义:

</>复制代码

  1. 如果参数为true,返回1. 如果参数为false,返回+0.
    这就是为什么我们布尔类型的值(truefalse)可以和数字相加。

参考:

12.5.6 Unary + Operator

12.8.3 The Addition Operator (+)

7.1.3 ToNumber(argument)

JavaScript中可以使用HTML的评论方式

在JavaScript中,使用

最新活动
阅读需要支付1元查看
<