wtfjs:一个接近20k关注的有趣JS项目(上)

![] + []; // -> ‘false’

![]; // -> false

所以我们尝试将[]false加起来。但是通过一些内部函数调用(binary + Operator - >ToPrimitive - >[[DefaultValue] ]),我们最终将右边的操作数转换为一个字符串:

![] + [].toString(); // ‘false’

将字符串作为数组,我们可以通过[0]来访问它的第一个字符:

“false”[0]; // -> ‘f’

现在,其余的是明显的,可以自己弄清楚!

[] 是 true, 但它不等于 true


数组是一个true,但是它不等于true

!![]       // -> true

[] == true // -> false

??? 说明:

以下是 ECMA-262 规范中相应部分的链接:

  • 12.5.9 逻辑非运算符 (!)

  • 7.2.13 抽象相等比较

null 是 false, 但又不等于 false


尽管 null 是 false,但它不等于 false

!!null; // -> false

null == false; // -> false

同时,其他的一些等于 false 的值,如 0 或 '' 等于 false 。

0 == false; // -> true

“” == false; // -> true

??? 说明:

跟前面的例子相同。这是一个相应的链接:

  • 7.2.13 抽象相等比较

document.all 是一个 object,但又同时是 undefined


⚠️ 这是浏览器 API 的一部分,对于 Node.js 环境无效 ⚠️

尽管 document.all 是一个 array-like object 并且通过它可以访问页面中的 DOM 节点,但在通过 typeof 的检测结果是 undefined

document.all instanceof Object; // -> true

typeof document.all; // -> ‘undefined’

同时,document.all 不等于 undefined

document.all === undefined; // -> false

document.all === null; // -> false

但是同时:

document.all == null; // -> true

??? 说明:

document.all 曾经是访问页面 DOM 节点的一种方式,特别是在早期版本的 IE 浏览器中。它从未成为标准,但被广泛使用在早期的 JS 代码中。当标准演变出新的 API 时(例如 document.getElementById)这个 API 调用就被废弃了,标准委员会必须决定如何处理它。因为它被广泛使用嗯他们决定保留这个 API 但引入一个有意的对 JavaScript 的标准的违反。其与 undefined 使用严格相等比较得出 false 而使用抽象相等比较 得出 true 是因为这个有意的对标准的违反明确地允许了这一点。

— “Obsolete features - document.all” at WhatWG - HTML spec — “Chapter 4 - ToBoolean - Falsy values” at YDKJS - Types & Grammar

最小值大于零


Number.MIN_VALUE 是最小的数字,大于零:

Number.MIN_VALUE > 0; // -> true

??? 说明:

Number.MIN_VALUE 是 5e-324 ,即可以在浮点精度内表示的最小正数,即可以达到零。它定义了浮点数的最高精度。

现在,整体最小的值是 Number.NEGATIVE_INFINITY ,尽管这在严格意义上并不是真正的数字。

— “为什么在 JavaScript 中0小于Number.MIN_VALUE?” at StackOverflow

  • 20.1.2.9 Number.MIN_VALUE

函数不是函数


⚠️ V8 v5.5 或更低版本中出现的 Bug(Node.js <= 7) ⚠️

你们所有人都知道的关于讨厌的 undefined 不是 function ,但是这个呢?

// Declare a class which extends null

class Foo extends null {}

// -> [Function: Foo]

new Foo() instanceof null;

// > TypeError: function is not a function

// >     at … … …

??? 说明:

这不是规范的一部分。这只是一个错误,现在它已被修复,所以将来不会有这个问题。

数组相加


如果您尝试两个数组相加呢?

[1, 2, 3] + [4, 5, 6]; // -> ‘1,2,34,5,6’

??? 说明:

会发生合并。一步一步地,它是这样的:

[1, 2, 3] +

[4, 5, 6][

// joining

(1, 2, 3)

].join() +

[4, 5, 6].join();

// concatenation

“1,2,3” + “4,5,6”;

// ->

(“1,2,34,5,6”);

数组中的逗号

======

您已经创建了一个包含 4 个空元素的数组。尽管如此,你还是会得到一个有三个元素的,因为后面的逗号:

let a = [, , ,];

a.length; // -> 3

a.toString(); // -> ‘,’

??? 说明:

尾逗号 (有时也称为“最后逗号”) 在向 JavaScript 代码中添加新元素、参数或属性时有用。如果您想添加一个新属性,您可以简单地添加一个新行,而不用修改以前的最后一行,如果该行已经使用了后面的逗号。这使得版本控制比较清洁和编辑代码可能不太麻烦。

— Trailing commas at MDN

数组相等是一个怪物


数组进行相等比较是一个怪物,看下面的例子:

[] == ‘’   // -> true

[] == 0    // -> true

[‘’] == ‘’ // -> true

[0] == 0   // -> true

[0] == ‘’  // -> false

[‘’] == 0  // -> true

[null] == ‘’      // true

[null] == 0       // true

[undefined] == ‘’ // true

[undefined] == 0  // true

[[]] == 0  // true

[[]] == ‘’ // true

[[[[[[]]]]]] == ‘’ // true

[[[[[[]]]]]] == 0  // true

[[[[[[ null ]]]]]] == 0  // true

[[[[[[ null ]]]]]] == ‘’ // true

[[[[[[ undefined ]]]]]] == 0  // true

[[[[[[ undefined ]]]]]] == ‘’ // true

??? 说明:

你应该非常小心留意上面的例子! 7.2.13 Abstract Equality Comparison 规范描述了这些行为。

undefined 和 Number


如果我们不把任何参数传递到 Number 构造函数中,我们将得到 0 。undefined 是一个赋值形参,没有实际的参数,所以您可能期望 NaN 将 undefined 作为参数的值。然而,当我们通过 undefined ,我们将得到 NaN 。

Number(); // -> 0

Number(undefined); // -> NaN

??? 说明:

根据规范:

  1. 如果没有参数传递给这个函数,让 n 为 +0 ;

  2. 否则,让 n 调用 ToNumber(value)

  3. 如果值为 undefined,那么 ToNumber(undefined) 应该返回 NaN.

这是相应的部分:

  • 20.1.1 Number 构造器函数

  • 7.1.3 ToNumber(argument)

parseInt 是一个坏蛋


parseInt 它以的怪异而出名。

parseInt(“f*ck”); // -> NaN

parseInt(“f*ck”, 16); // -> 15

**??? 说明:

** 这是因为 parseInt 会持续通过解析直到它解析到一个不识别的字符,'f*ck' 中的 f 是 16 进制下的 15

解析 Infinity 到整数也很有意思…

//

parseInt(“Infinity”, 10); // -> NaN

// …

parseInt(“Infinity”, 18); // -> NaN…

parseInt(“Infinity”, 19); // -> 18

// …

parseInt(“Infinity”, 23); // -> 18…

parseInt(“Infinity”, 24); // -> 151176378

// …

parseInt(“Infinity”, 29); // -> 385849803

parseInt(“Infinity”, 30); // -> 13693557269

// …

parseInt(“Infinity”, 34); // -> 28872273981

parseInt(“Infinity”, 35); // -> 1201203301724

parseInt(“Infinity”, 36); // -> 1461559270678…

parseInt(“Infinity”, 37); // -> NaN

也要小心解析 null

parseInt(null, 24); // -> 23

??? 说明:

它将 null 转换成字符串 'null' ,并尝试转换它。对于基数 0 到 23,没有可以转换的数字,因此返回 NaN。在 24,“n” ,第 14 个字母被添加到数字系统。在 31,“u” ,添加第 21 个字母,可以解码整个字符串。在 37 处,不再有可以生成的有效数字集,并返回 NaN 。

— “parseInt(null, 24) === 23… wait, what?” at StackOverflow

不要忘记八进制:

parseInt(“06”); // 6

parseInt(“08”); // 8 如果支持 ECMAScript 5

parseInt(“08”); // 0 如果不支持 ECMAScript 5

??? 说明:

这是因为 parseInt 能够接受两个参数,如果没有提供第二个参数,并且第一个参数以 0 开始,它将把第一个参数当做八进制数解析。

parseInt 总是把输入转为字符串:

parseInt({ toString: () => 2, valueOf: () => 1 }); // -> 2

Number({ toString: () => 2, valueOf: () => 1 }); // -> 1

解析浮点数的时候要注意

parseInt(0.000001); // -> 0

parseInt(0.0000001); // -> 1

parseInt(1 / 1999999); // -> 5

??? 说明: ParseInt 接受字符串参数并返回一个指定基数下的证书。ParseInt 也去除第一个字符串中非数字字符(字符集由基数决定)后的内容。0.000001 被转换为 "0.000001" 而 parseInt 返回 0。当 0.0000001 被转换为字符串时它被处理为 "1e-7" 因此 parseInt 返回 11/1999999 被转换为 5.00000250000125e-7 而 parseInt 返回 5

true 和 false 数学运算


我们做一些数学计算:

true +

true(

// -> 2

true + true

) *

(true + true) -

true; // -> 3

嗯… ???

??? 说明:

我们可以用 Number 构造函数强制转化成数值。很明显,true 将被强制转换为 1 :

Number(true); // -> 1

一元加运算符尝试将其值转换成数字。它可以转换整数和浮点的字符串表示,以及非字符串值 true ,false 和 null 。如果它不能解析特定的值,它将转化为 NaN 。这意味着我们可以更容易地强制将 true 换成 1

+true; // -> 1

当你执行加法或乘法时,ToNumber方法调用。根据规范,该方法返回:

如果 参数 is true , 返回 1 。如果 参数 是 false 返回 +0

这就是为什么我们可以进行进行布尔值相加并得到正确的结果

相应部分:

  • 12.5.6 一元 + 运算符

  • 12.8.3 加法运算符(+

  • 7.1.3 ToNumber(argument)

HTML 注释在 JavaScript 中有效


你会留下深刻的印象,<!-- (这是 HTML 注释)是一个有效的 JavaScript 注释。

// 有效注释

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值