skylar艺璇

运算符中的一些小技巧

  • 记下一些关于运算符的小技巧或容易出错的地方

%运算符


取余运算符运算结果的正负号由第一个运算子的正负号决定,比如:

1
2
-1 % 2 // -1
1 % -2 // 1

所以有时候对负数取余会出现错误,使用绝对值函数可以避免错误:

1
2
3
4
5
6
// 会出错
function isOdd(n) {
return n % 2 === 1;
}
isOdd(-5) // false
isOdd(-4) // false

1
2
3
4
5
6
// 正确了
function isOdd(n) {
return Math.abs(n % 2) === 1;
}
isOdd(-5) // true
isOdd(-4) // false

+运算符


+运算符与其他运算符不太一样,我们知道它可以用来连接字符串操作,是因为用+运算符的时候它通常会将其他类型的值转为字符串,但是除了它比如说-运算符等都会将其他类型的值转换为数值,像这样:

1
2
3
var now = new Date();
typeof (now + 1) // "string"
typeof (now - 1) // "number"

当运算子中出现对象的时候:

1
2
3
4
1 + [1,2]
// "11,2"
1 + {a:1}
// "1[object Object]"

则先调用该对象的valueOf方法。如果返回结果为原始类型的值,则转换为字符串;否则继续调用该对象的toString方法,然后转换为字符串。
但是:

1
2
3
4
{a:1} + 1
// 1
({a:1})+1
"[object Object]1"

这是为什么呢?此时{a:1}被当做了代码块处理,而这个代码块没有返回值,所以整个表达式就返回1了。但是放在了圆括号中的{a:1},因为js预期()中是一个值,所以它就又被当做对象处理了。

特殊表达式:

  • 空数组+空数组

先调用valueOf()返回空数组本身,再调用toString(),返回空字符串。

1
2
[] + []
// ""
  • 空数组+空对象

[]得到’’,{}得到”[object Object]”

1
2
[] + {}
// "[object Object]"
  • 空对象+空数组

{}被视作代码块省略,+[]就是将[]转换为数值的意思了得到0.

1
2
{} + []
// 0
  • 空对象+空对象

同样{}被当做代码块省略了,+{}转数值得到NaN

1
2
{} + {}
// NaN

如果第一个空对象不被当做空代码块的话:

1
2
3
4
5
6
7
8
9
10
11
12
({}) + {}
// "[object Object][object Object]"
({} + {})
// "[object Object][object Object]"
console.log({} + {})
// "[object Object][object Object]"
var a = {} + {};
a
// "[object Object][object Object]"

此外,当+运算符作为数值运算符放在其他值前面的时候,可以用于将任何值转为数值,就像Number函数那样:

1
2
3
+true // 1
+[] // 0
+{} // NaN

!取反运算符


!取反运算符连续对同一个值进行取反运算等于将其转换为对应的布尔值,就像Boolean函数那样:

!!x

// 等同于

Boolean(x)

此外,如果我们想排除null这个对象,可以这样写:

1
2
3
if(!!x){
//do something!
}

这是因为:!!null 值是 false,其他的 object !!obj 值都是 true。

~否运算符


~运算符是根据值的二进制二进制形式进行运算的。

~ 3 // -4

它的运算原理就是根据数值的32位二进制整数形式运算,补码存储的原理如果是负数,需要将取反后的值减一再取反然后加上负号。
比较麻烦,但是我们可以记成一个值与它取反后的值相加等于-1.

~~2.9
// 2

两次否运算能够对小数取整,并且这是取整方法中最快的一种。

^异或运算符


两次异或运算交换两个数的值:

1
2
3
4
5
6
7
var a = 10;
var b = 99;
a^=b, b^=a, a^=b;
a // 99
b // 10

<< 左移运算符


左移0位可用于取整:

1
2
3
4
5
13.5 << 0
// 13
-13.5 << 0
// -13

左移运算可以将颜色的RGB值转为HEX值:

1
2
3
4
5
6
7
8
9
var color = {r: 186, g: 218, b: 85};
// RGB to HEX
var rgb2hex = function(r, g, b) {
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).substr(1);
}
rgb2hex(color.r,color.g,color.b)
// "#bada55"

>> 右移运算


右移运算可以模拟2的整除运算:

1
2
3
4
5
6
7
8
9
10
11
5 >> 1
// 相当于 5 / 2 = 2
21 >> 2
// 相当于 21 / 4 = 5
21 >> 3
// 相当于 21 / 8 = 2
21 >> 4
// 相当于 21 / 16 = 1

此外,void运算符的作用是用来执行一个表达式,然后返回undefined,而且它的运算符优先级也比较高void 4+7 实际上等同于 (void 4) +7。一般运算符是左结合的,但是=和三目运算符?:却是右结合的:

1
2
3
4
w = x = y = z;
q = a?b:c?d:e?f:g;
w = (x = (y = z));
q = a?b:(c?d:(e?f:g));