前言
背景
例子
1. true + false
Number(true); // -> 1
Number(false); // -> 0
1 + 0; // -> 1
? 说明:
布尔值被转换为它们的数字表示
2. true 是 false
!!"false" == !!"true"; // -> true
!!"false" === !!"true"; // -> true
? 说明:
考虑一下这一步:
true == "true"; // -> true
false == "false"; // -> false
// 'false' 不是空字符串,所以它的值是 true
!!"false"; // -> true
!!"true"; // -> true
3. baNaNa
"b" + "a" + +"a" + "a"; // baNaNa
用 JavaScript 写的老派笑话:
"foo" + +"bar"; // -> 'fooNaN'
? 说明:
这个表达式可以转化成 'foo' + (+'bar')
,但无法将'bar'
强制转化成数值。
4. NaN
不是一个 NaN
NaN === NaN; // -> false
? 说明:
规范严格定义了这种行为背后的逻辑:
遵循 IEEE 的“NaN”的定义:
5. 它是 fail
你不会相信,但...
(![] + [])[+[]] +
(![] + [])[+!+[]] +
([![]] + [][[]])[+!+[] + [+[]]] +
(![] + [])[!+[] + !+[]];
// -> 'fail'
? 说明:
将大量的符号分解成片段,我们注意到,以下表达式经常出现:
![] + []; // -> 'false'
![]; // -> false
所以我们尝试将[]
和false
加起来。 但是通过一些内部函数调用(binary + Operator
- >ToPrimitive
- >[[DefaultValue]
]),我们最终将右边的操作数转换为一个字符串:
![] + [].toString(); // 'false'
将字符串作为数组,我们可以通过[0]
来访问它的第一个字符:
"false"[0]; // -> 'f'
现在,其余的是明显的,可以自己弄清楚!
6. []
是 true
, 但它不等于 true
!![] // -> true
[] == true // -> false
? 说明:
数组是一个true
,但是它不等于true
。
7. null
是 false, 但又不等于 false
尽管 null
是 false
,但它不等于 false
。
!!null; // -> false
null == false; // -> false
同时,其他的一些等于 false 的值,如 0
或 ''
等于 false
。
0 == false; // -> true
"" == false; // -> true
? 说明:
跟前面的例子相同。这是一个相应的链接:
- 7.2.13 抽象相等比较
8. document.all
是一个 object,但又同时是 undefined
尽管 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
? 说明:
9. 最小值大于零
Number.MIN_VALUE
是最小的数字,大于零:
Number.MIN_VALUE > 0; // -> true
? 说明:
10. 函数不是函数
你们所有人都知道的关于讨厌的 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 … … …
? 说明:
这不是规范的一部分。这只是一个错误,现在它已被修复,所以将来不会有这个问题。
11. 数组相加
如果您尝试两个数组相加呢?
[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");
12. 数组中的逗号
您已经创建了一个包含 4 个空元素的数组。尽管如此,你还是会得到一个有三个元素的,因为后面的逗号:
let a = [, , ,];
a.length; // -> 3
a.toString(); // -> ',,'
? 说明:
13. 数组相等是一个怪物
数组进行相等比较是一个怪物,看下面的例子:
[] == '' // -> 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 规范描述了这些行为。
14. undefined
和 Number
如果我们不把任何参数传递到 Number
构造函数中,我们将得到 0
。undefined
是一个赋值形参,没有实际的参数,所以您可能期望 NaN
将 undefined
作为参数的值。然而,当我们通过 undefined
,我们将得到 NaN
。
Number(); // -> 0
Number(undefined); // -> NaN
? 说明:
根据规范:
- 如果没有参数传递给这个函数,让
n
为+0
; - 否则,让
n
调用ToNumber(value)
- 如果值为
undefined
,那么ToNumber(undefined)
应该返回NaN
.
15. 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
? 说明:
不要忘记八进制:
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
返回 1
。1/1999999
被转换为 5.00000250000125e-7
而 parseInt
返回 5
。
16. 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
方法调用。 根据规范,该方法返回:
这就是为什么我们可以进行进行布尔值相加并得到正确的结果
相应部分:
- 12.5.6 一元
+
运算符 - 12.8.3 加法运算符(
+
) - 7.1.3 ToNumber(
argument
)
17. HTML 注释在 JavaScript 中有效
你会留下深刻的印象,<!--
(这是 HTML 注释)是一个有效的 JavaScript 注释。
// 有效注释
<!-- 也是有效的注释
? 说明:
感动吗? 类似 HTML 的注释旨在允许不理解标签的浏览器优雅地降级。这些浏览器,例如 Netscape 1.x 已经不再流行。因此,在脚本标记中添加 HTML 注释是没有意义的。
由于 Node.js 基于 V8 引擎,Node.js 运行时也支持类似 HTML 的注释。
18. NaN
不是一个数值
尽管 NaN
类型是 'number'
,但是 NaN
不是数字的实例:
typeof NaN; // -> 'number'
NaN instanceof Number; // -> false
? 说明:
typeof
和 instanceof
运算符的工作原理:
- 12.5.5
typeof
操作符 - 12.10.4 Runtime Semantics: InstanceofOperator(
O
,C
)
19. []
和 null
是对象
typeof []; // -> 'object'
typeof null; // -> 'object'
// 然而
null instanceof Object; // false
? 说明:
typeof
运算符的行为在本节的规范中定义:
根据规范,typeof
操作符返回一个字符串 。对于没有 [[Call]]
实现的 null
、普通对象、标准特异对象和非标准特异对象,它返回字符串 "object“
。
但是,您可以使用 toString
方法检查对象的类型。
Object.prototype.toString.call([]);
// -> '[object Array]'
Object.prototype.toString.call(new Date());
// -> '[object Date]'
Object.prototype.toString.call(null);
// -> '[object Null]'
20. 神奇的数字增长
999999999999999; // -> 999999999999999
9999999999999999; // -> 10000000000000000
? 说明:
这是由 IEEE 754-2008 二进制浮点运算标准引起的。
21. 0.1 + 0.2
精度计算
来自 JavaScript 的知名笑话。0.1
和 0.2
相加是存在精度错误的
0.1 +
0.2(
// -> 0.30000000000000004
0.1 + 0.2
) ===
0.3; // -> false
? 说明:
浮点计算坏了:
这个问题是众所周知的,甚至有一个网站叫 0.30000000000000004.com。
22. 扩展数字的方法
您可以添加自己的方法来包装对象,如 Number
或 String
。
Number.prototype.isOne = function() {
return Number(this) === 1;
};
(1.0).isOne(); // -> true
(1).isOne(); // -> true
(2.0)
.isOne()(
// -> false
7
)
.isOne(); // -> false
? 说明:
显然,您可以像 JavaScript 中的任何其他对象一样扩展 Number
对象。但是,不建议扩展不属于规范的行为定义。以下是 Number
属性的列表:
23. 三个数字的比较
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 > 2 >= 1; // true
24. 有趣的数学
通常 JavaScript 中的算术运算的结果可能是非常难以预料的。 考虑这些例子:
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
? 说明:
前四个例子发生了什么?这是一个小表,以了解 JavaScript 中的添加:
Number + Number -> addition
Boolean + Number -> addition
Boolean + Boolean -> addition
Number + String -> concatenation
String + Boolean -> concatenation
String + String -> concatenation
剩下的例子呢?在相加之前,[]
和 {}
隐式调用 ToPrimitive
和 ToString
方法。
25. 字符串不是 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']
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!