怪异的JS系列

  |  
 阅读次数

怪异的JavaScript系列(一)

[ ]等于![ ]

[] == ![] // -> true

相等(==)判断操作会将两边的类型都转换为数字(number),然后再比较。

因为[]![]都会转换为0。我们可以理解[]是一个数组,只不过为空而已,那么为true。右侧![]则为falsefalse然后转换为数字0左侧[]直接换为数字,因为空数组会转换为0,所以尽管我们认为[]为true,这里却变成了0。
简算过程:

1
2
3
4
+[] == +![]
0 == +false
0 == 0
true

true 是 false

!!'false' ==  !!'true'  // -> true
!!'false' === !!'true' // -> true

true是一个真值,用1表示;字符串的“true”则为NaN

true == 'true'    // -> false
false == 'false'  // -> false

‘false’是一个有意义的字符串。

baNaNa

'b' + 'a' ++ 'a' + 'a' // -> baNaNa

这是一个旧笑话,不过改进过的。原始的长这样:

'foo' ++ 'bar' // -> 'fooNaN'

该表达式以'foo' + (+'bar')的形式计算,因为bar不是数字,所以转换为NaN

NaN不等于NaN

NaN === NaN // -> false

根据 === 的算法,我们可以容易理解为什么为false。

fail

(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] // -> fail

如果我们仔细观察序列的规律,会发现下面的模式出现很多次:

(![]+[]) // -> 'false'
![]      // -> false    

因此,我们尝试将[]false相加。但是根据内部一些列函数的计算(binary + Operator -> ToPrimitive -> [[DefaultValue]]),右侧的[]最终转换为string:

(![]+[].toString()) // 'false'

对于一个字符串,我们就可以通过下标来获取对应的字符:

'false'[0] // -> 'f'        

剩下的都很直观,除了i很取巧。fail中的i是通过在falseundefined中获取第十个下标对应的字符而得到。

[ ]包含值,但不是true

null不等于false

document.all是一个对象,不过是 undefined

⚠️这个是前端浏览器API,在Nodejs环境无法使用。

尽管document.all可以返回一个像数组一样的对象,可以用来访问DOM节点。但是呢,通过typeof查看document.all,你会惊讶地发现类型是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)后,document.all就被淘汰了。标准委员会不知道怎么处理它。可是因为它已经被广泛使用,所以委员会觉得保留它,但是违背了JavaScript的规范。

最小值比0还大

Number.MIN_VALUE是最小的数,但是它比0还大。

Number.MIN_VALUE > 0 // -> true

因为Number.MIN_VALUE5e-324。也就是说即使最小的值也可以用浮点数表示出来,虽然离0很接近,但是依然比0大。其实最小的数是Number.NEGATIVE_INFINITY,尽管它不是一个实际存在的数。

JS常见陷阱

  |  
 阅读次数

JavaScript中8个常见的陷阱

1. 数组元素排序

JavaScript默认使用字典序(alphanumeric)来排序。因此,[1,2,5,10].sort()的结果是[1, 10, 2, 5]

如果你想正确的排序,应该这样做:[1,2,5,10].sort((a, b) => a - b)

2. new Date()

new Date()的使用方法有:

  • 不接收任何参数:返回当前时间;
  • 接收一个参数x: 返回1970年1月1日 + x毫秒的值。
  • new Date(1, 1, 1)返回1901年2月1号。
  • new Date(2016, 1, 1)不会在1900年的基础上加2016,而只是表示2016年。

3. 替换函数(replace)

let s = "bob"
const replaced = s.replace('b', 'l')
replaced === "lob" // 只会替换掉第一个b
s === "bob" // 并且s的值不会变  

如果想把所有b都替换掉,要使用正则:

"bob".replace(/b/g, 'l') === 'lol'

4. 谨慎对待比较运算

// 这些可以
‘abc’ === ‘abc’ // true
1 === 1 // true
// 然而这些不行
[1,2,3] === [1,2,3] // false
{a: 1} === {a: 1} // false
{} === {} // false

因为[1,2,3]和[1,2,3]是两个不同的数组,只是它们的元素碰巧相同。因此,不能简单的通过===来判断。

添加自定义shell

  |  
 阅读次数

添加自定义github.shell

1
2
3
4
5
$ echo $PATH  // 打印 路径
$ cd /home/LiSC/bin // 转到第一个路径
$ mkdir /home/LiSC/bin // 创建文件夹
$ vim github.shell // 创建文件[把shell脚本复制粘贴]
$ chmod +x github.shell // 文件权限属性设置 => 用来变更文件或目录的权限

附:shell

1
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/bin/bash
## Coptyright 2016 The LiShiChen Library Authors. All rights reserved.
## Use of this source code is governed by a Apache-style
## license that can be found in the LICNESE file.
##
## Git(Github.com) Common Client Commands.
##
## @authors hjboss <hongjiangproject@gmail.com> 2018-04 $$
## @version 1.0.0
GIT=`/usr/bin/which git`
HOST='git@github.com'
NAME='SunOfHomeBoy'
SCRIPT=`basename $0`

case "$1" in
"add")
if [ $# -lt 2 ] || [ "$2" == "*" ]; then
$GIT add --all
else
$GIT add "$2"
fi
;;

"ci")
if [ $# -lt 2 ]; then
$GIT commit -a -m "Initial commit"
else
$GIT commit -a -m "$2"
fi
$GIT push -u origin master
;;

"co")
if [ $# -lt 2 ]; then
echo "版本庫名稱不能空值"
elif [ $# -eq 2 ]; then
$GIT clone "$HOST:$NAME/$2.git"
else
$GIT clone "$HOST:$2/$3.git"
fi
;;

"rm")
if [ $# -lt 2 ]; then
echo "刪除文件名不能空值"
exit
fi
$GIT rm "$2"
;;

"up")
$GIT pull
;;

"st")
$GIT status
;;

"help")
echo "用法: $SCRIPT <subcommand> [args]"
echo "版本: 1.0.0"
echo "最常用的子命令:"
echo " add 添加文件内容至索引"
echo " ci 记录变更到版本库并且更新至github.com"
echo " co 将给定名称的版本库克隆到一个新目录"
echo " rm 从工作区和索引中删除文件"
echo " up 本地分支更新到最新版本"
echo " st 显示工作区状态"
;;

"version")
echo "$SCRIPT version 1.0.0"
;;

*)
echo "使用$SCRIPT help得到用法"
;;
esac

自定义NPM脚本

sbin & bin 区别 root可以访问 sbin 下的脚本

/usr/local/sbin/npm.shell

1
2
#!/bin/sh
npm --registry=https://registry.npm.taobao.org $*

$*: 属于 process 环境变量