# js边角料
+0 === -0 //true
NaN === NaN // false
NaN !== NaN // true
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
2
3
4
5
6
- 1、一些假值:
false,null,0,"",undefined,NaN - 2、使用
.link()创建链接
// --- before ---
let b = `<a herf="www.google.com">google</a>`;
// --- after ---
let b = 'google'.link('www.google.com');
//"<a href="www.google.com">google</a>"
2
3
4
5
6
- 3、使用当前时间创建一个随机数
// --- before ---
let b = 0 | Math.random() * 100
// --- after ---
let a;
a = new Date % 100; // 两位随机数
a = new Date % 1000; // 三位随机数
a = new Date % 10000; // 四位随机数...依次类推
// 不要在快速循环中使用,因为毫秒可能没有变化;
2
3
4
5
6
7
8
9
- 4、一些可以替代 undefined 的操作
""._,1.._和0[0]void 0会比写undefined要快一些
- 5、使用
1/0来替代Infinity
// --- before ---
[Infinity, -Infinity]
// --- after ---
[1/0, -1/0]
2
3
4
5
- 6、使用
!+"\v1"快速判断 IE8 以下的浏览器 - 7、for 循环条件的简写
// --- before ---
for(let i = 0; i < arr.length; i++) {...}
// --- after ---
for(let i = arr.length; i--;) {...} // 注意 i-- 后面的分号别漏了
2
3
4
5
- 8、
null >= 0为true - 9、
''>=0为true
# 只用这 6 个字符,就可以写出任意 JavaScript 代码
6 个字符
[]()!+
# 6 个字符的原理
我们之所以能够抛开其他字符不用,要
归功于 JavaScript 的类型系统和数据类型转换机制。这 6 个字符是这样各显神通的:[]可以用来创建数组,!和+可以在数组上执行一些操作,再用()给这些操作分组。
先看一个简单的数组:
[]
数组前加上!会把它转成布尔值。数组被认为是真值,因此取非之后变成了false:
![] === false
除非转换为类似类型,否则无法将不同类型的值加在一起。JavaScript 在进行转换时遵循一个预定义的规则:
- 在表达式
2 + true中,JavaScript 会将true转成数字,得到表达式2+1。 - 在表达式
2 + "2"中,JavaScript 会将数字转成字符串,得到2 + "2" === "22"。
WARNING
这些转换规则还不算糟糕,但是对于其他类型,好戏马上来了。
# JavaScript 数组强制转换
数组相加会转换成字符串并连接起来。空数组转换为空字符串,因此将两个数组相加将得到空字符串。
[] + [] === "" + "" === ""
数组跟其他类型值相加时也一样:
![] + [] === "false" + "" === "false"
惊不惊喜?我们得到了目标字符串"self"所包含的几个字符!如果我们能产生一些数字,就可以按正确的顺序提取所需的字符:
"false"[3] === "s"
(![] + [])[3] === "s"
2
# 生成数字
前面提到了,可以把数组转成布尔值。那如果用加号+把它转成数字会怎样?
+[] === ???
JavaScript 会尝试调用数组的valueOf方法,但是发现不存在这个方法,然后就转而调用toString()方法了。因此上面的代码等效于:
+[] === +""
将字符串转换为数字将产生以下结果:
+"42" === 42
+"esg" == NaN
+"" === 0
2
3
空字符串是一个 false值,跟 null,undefined和数字零类似,因此将其中任何一个转换为数字都会变成零:
+null === 0
+undefined === 0
+false === 0
+NaN === 0
+"" === 0
2
3
4
5
因此,将数组转换为数字需要先将其转换为字符串,最后转成 0:
+[] === +"" === 0
第一个数字已经造出来了!我们还需要更多数字,继续:
!0 === !false
!false === true
!0 === true
2
3
将 0 取否就得到一个为真的布尔值。为真的布尔值转成数字,就是1:
+true === 1
有了 1,自然就可以得到2,所谓道生一,一生二,二生三,三生万物……
用上面的转换大法,可以轻松得到我们想要的这些数字:
1 === +true == +(!0) ==== +(!(+[])) === +!+[]1 === +!+[]2 === +!+[] +!+[]3 === +!+[] +!+[] +!+[]4 === +!+[] +!+[] +!+[] +!+[]
# 临门一脚,大功告成
总结下这些规则:
- 数组属于真值,取否就得到 false:
![] // false - 数组相加时会转换成字符:
[] + [] // "" - 空数组转成数字得到 0,再去否得到 true,再转成数字得到1:
+(!(+[])) === 1
根据这些规则,我们就能得到想要的字符串。看下面这个示意图就很清楚了:
![] + [] === "false"+!+[] === 1(![] + [])[3] + (![] + [])[4] + (![] + [])[2] + (![] + [])[0]^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ "false" "false" "false" "false" ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ s e l f
最终的表达式就是这样:
(![] + [])[+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]] +(![] + [])[+[]]
整理下空格和换行,就是一行代码:
(![]+[])[+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]]+(![]+[])[+[]]
# 骂人彩蛋
(!(~+[])+{})[--[~+""][+[]]*[~+[]]+~~!+[]]+({}+[])[[~!+[]]*~+[]];//sb
([][[]] + [])[+!![]] + ([] + {})[!+[] + !![]];//nb
2
3
# 默认值策略
但是默认值生效的前提是:ES6内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [z = 1] = [undefined];
console.log(z); // 1
let [k = 1] = [null];
console.log(k); // null
2
3
4
5
6
7
- 对象也可以使用默认值,但是前提是:
对象的属性值严格等于undefined。
var {x = 3} = {x: undefined};
console.log(x); // 3
var {y = 3} = {y: null};
console.log(y); // null
2
3
4
5
# 20个古怪表达式,并要猜出其输出结果
true + false//1
**1.**//?????啥玩意
[1, 2, 3] + [4, 5, 6]//'1,2,34,5,6'
0.2 + 0.1 === 0.3//(0.30000000000000004)false
10,2//2
!!""//false
+!![]//1
true == "true"//false
010 - 03//5(一个数字以0开头,那么在JavaScript中它就被当作一个八进制数字)
// 0b开头,那么它在JavaScript中被视为二进制数字。
// 0x开头,它在JavaScript中被当作一个十六进制数字。
''- -''//0
// -'' 为 0
// '' 为0
null + 0//0
0/0//NaN
1/0 === 10 ** 1000//true,
// 当除数不是0时,JavaScript认为这个表达式的结果是Infinity
// 10**1000是一个很大数字,JS 无法正确表示这个数字。(JavaScript中最高的整数值是2^53-1)。所以10 * 1000也被当作无限大(Infinity)。
true++//错误语法
"" - 1//-1
(null - 1) - "1"//-2
38 * 4343 * 2342+ (“true” — 0)// NaN
// 在JavaScript的数字运算中,只要有一个值是NaN
5 + !5 + !!5//6
[] + [1] + 2//12
1 + 2 + "3"// 33
// JavaScript 从左到右执行这些操作。当数字3与字符串3相加时,字符串连接将优先进行。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47