资讯专栏INFORMATION COLUMN

怪异的JavaScript系列(三)

XboxYan / 1597人阅读

摘要:本文的思想源自于在上的演讲。我收集这些例子的主要目的是将它们整理并清楚理解它们的原理。着主要是因为大括号也是函数定义语法的一部分。自从年双十一正式上线,累计处理了亿错误事件,得到了金山软件等众多知名用户的认可。

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

原文: What the f*ck JavaScript?

译者: Fundebug

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

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

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

return

下面的函数返回的结果竟然不是对象{b:10}

(function () {
  return
  {
    b : 10
  }
})() // -> undefined

不过,如果稍微改写一下,就不一样了:

(function () {
  return {
    b : 10
  }
})() // -> { b: 10 }

这主要是因为有一个自动行尾加分号的机制在作怪,会自动在很多新行的行尾添加分号。在第一个例子中,实际上是在return后面添加了分号。

(function () {
  return ;
  {
    b : 10
  }
})() // -> undefined

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

0.1+0.2=?

一个众所周知的笑话就是0.1加上0.2竟然不等于0.3。

0.1 + 0.2 // -> 0.30000000000000004
(0.1 + 0.2) === 0.3 // -> false

在StackOverflow上有关提到这样的问题“浮点数加法运算坏了(Is floating point math broken?)”:

你的程序中0.2和0.3会在底层用相近的数据表达。double类型数据中离0.2最近的数要比0.2大一点点。离0.3最近的double类型数据又刚好比0.3小一点点。所以,结果就是0.1+0.2的结果比0.3大。

这个问题非常出名,以至于有一个专门的网站0.30000000000000004.com。在所有使用浮点计算的语言中都有这个问题,不止JavaScript。

神奇的加法操作
999999999999999  // -> 999999999999999
9999999999999999 // -> 10000000000000000

10000000000000000       // -> 10000000000000000
10000000000000000 + 1   // -> 10000000000000000
10000000000000000 + 1.1 // -> 10000000000000002

这个是依据IEEE 754-2008标准确定的二进制浮点运算。当数值大到这个程度,它会取整到最近的偶数。参考:

6.1.6 The Number Type

IEEE 754 on Wikipedia

为Number自定义

你可以为NumberString添加自定义函数:

Number.prototype.isOne = function () {
  return Number(this) === 1
}

1.0.isOne() // -> true
1..isOne()  // -> true
2.0.isOne() // -> false
(7).isOne() // -> false

你可以想操纵其它对象一样去扩展Number对象。不过,如果定义的函数不在它本身的定义规范(Specification)中,那么不建议这么做。这里是一个参考列表:

20.1 Number Objects

3个number比较
1 < 2 < 3 // -> true
3 > 2 > 1 // -> false

我们来看看具体的执行过程就明白了:

1 < 2 < 3 // 1 < 2 -> true
true  < 3 // true -> 1
1     < 3 // -> true

3 > 2 > 1 // 3 > 2 -> true
true  > 1 // true -> 1
1     > 1 // -> false
有趣的数学
3  - 1  // -> 2
 3  + 1  // -> 4
"3" - 1  // -> 2
"3" + 1  // -> "31"

"" + "" // -> ""
[] + [] // -> ""
{} + [] // -> 0
[] + {} // -> "[object Object]"
{} + {} // -> "[object Object][object Object]"

"222" - -"111" // -> 333

[4] * [4]       // -> 16
[] * []         // -> 0
[4, 4] * [4, 4] // NaN

到底是为什么呢? 下面有一个表供快速参考:

Number  + Number  -> addition
Boolean + Number  -> addition
Boolean + Boolean -> addition
Number  + String  -> concatenation
String  + Boolean -> concatenation
String  + String  -> concatenation

那么其他例子呢?对于[]{},toPrimitive和toString方法会在加法操作前被隐式地调用。

12.8.3 The Addition Operator (+)

[7.1.1 ToPrimitive(input [,PreferredType])](https://www.ecma-internationa...

7.1.12 ToString(argument)

正则也可以做加法?
// Patch a toString method
RegExp.prototype.toString = function() {
  return this.source
}

/7/ - /5/ // -> 2

参考: 21.2.5.10 get RegExp.prototype.source

箭头函数
let f = () => 10
f() // -> 10

好的,但是下面这个呢:

let f = () => {}
f() // -> undefined

你也许期待着返回{},而不是undefined。着主要是因为大括号也是函数定义语法的一部分。如果你真想返回大括号,可以这么写:

let f = () => ({})
f() // -> {}
Math.max()比Math.min()小
Math.min(1,4,7,2)  // -> 1
Math.max(1,4,7,2) // -> 7
Math.min() // -> Infinity
Math.max() // -> -Infinity
Math.min() > Math.max() // -> true

原因: Why is Math.max() less than Math.min()? by Charlie Harvey

String不是String的实例
"str" // -> "str"
typeof "str" // -> "string"
"str" instanceof String // -> false

构造函数String返回一个字符串:

typeof String("str")   // -> "string"
String("str")          // -> "str"
String("str") == "str" // -> true

如果我们用new来构建的话:

new String("str") == "str" // -> true
typeof new String("str")   // -> "object"

竟然变成了一个对象!

new String("str") // -> [String: "str"]

参考: 21.1.1 The String Constructor

往期参考

Fundebug博客 - 怪异的JavaScript系列(一)

Fundebug博客 - 怪异的JavaScript系列(二)

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

版权声明

转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/04/16/javascript-werid-series-3/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94608.html

相关文章

  • 前端知识点总结

    摘要:知识点一和浏览器渲染模式文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样的文档类型定义来解析文档。知识点二文件类型声明仅有一型。知识点三常用整理常用整理 知识点一:DOCTYPE和浏览器渲染模式 文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样...

    AprilJ 评论0 收藏0
  • 前端知识点总结

    摘要:知识点一和浏览器渲染模式文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样的文档类型定义来解析文档。知识点二文件类型声明仅有一型。知识点三常用整理常用整理 知识点一:DOCTYPE和浏览器渲染模式 文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样...

    TNFE 评论0 收藏0
  • 前端知识点总结

    摘要:知识点一和浏览器渲染模式文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样的文档类型定义来解析文档。知识点二文件类型声明仅有一型。知识点三常用整理常用整理 知识点一:DOCTYPE和浏览器渲染模式 文档类型,一个文档类型标记是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样...

    LittleLiByte 评论0 收藏0
  • 怪异JavaScript系列(二)

    摘要:函数不是函数这是一个低版本的,,或则。对应的进制数为。因此最安全的方法是调用的时候指定进制。它会将字符串形式的整数转换为,非字符串的,,和也会被转换。对于不能转换的值,返回。而浏览器主要指系列,其实已经没有必要支持这个特性了。 译者按: JavaScript有很多坑,经常一不小心就要写bug。 原文: What the f*ck JavaScript? 译者: Fundebug ...

    YacaToy 评论0 收藏0

发表评论

0条评论

XboxYan

|高级讲师

TA的文章

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