【本文会持续升级!】
+
运算符使用 +
运算符可以把其余类型转换成数字类型,但在使用时要注意表达式的结构,避免被解析成字符串连接符。
+'123'; // 123+'123'+'456'; // "123456"+'123'+(+'456'); // 579
~~
位运算符按位非(~
)实质上是 对数字求负,而后减1。详细的解决过程请看 w3school: 位运算符。
~1; // -2~-1; // 0
那么再次执行按位非就可取回原值:。
~~1; // 1~~'1'; // 1
需要注意的是,~~
的方式只适合解决 32 位以下整数,若是浮点数会被取整。
~~1.2; // 1~~-1.2; // -1
与 +
运算符相比,~~
运算符会把 undefined
或者者不能转换成数字的值解决成 0
,在某些业务计算场景下这样的解决是有方便之处的。
+undefined; // NaN+'abc'; // NaN~~undefined; // 0~~'abc'; // 0
实际上, +
运算符和 ~~
运算符都相当于使用 Number()
函数来解决,所以我们依然需要关注少量特殊值的转换:
+'123', ~~'123'; // 123+undefined, ~~undefined; // NaN+null, ~~null; // 0+true, ~~true; // 1+false, ~~false; // 0+[1], ~~[1]; // 1
当被转换值本身就是数字类型时,我们需要 小心被当成八进制数解决:
+010; // 8+'010'; // '10'
+
运算符紧跟一个空字符串,即可以把其余类型转换成字符串类型。
1+''; // "1"undefined+''; // "undefined"null+''; // "null"true+''; // "true"[1,2]+''; // "1,2"
当被转换对象存在 toString()
的原型方法时,这种转换方式相当于调用了 toString()
函数:
new Date()+''; // "Thu May 16 2019 20:42:43 GMT+0800 (China Standard Time)"new Date().toString(); // "Thu May 16 2019 20:42:43 GMT+0800 (China Standard Time)"var o = {a: 1};o+''; // "[object Object]"o.toString(); // "[object Object]"
因为逻辑非(!
)返回的肯定是布尔值,所以通过双取反就可转换成布尔值。
!!0; // false!!undefined; // false!!'abc'; // true!![] // true!!{} // true
逻辑与(&&
)和逻辑或者(||
)运算都是简便运算,即假如第一个运算数决定了结果,就不再计算第二个运算数,这就是短路求值。
利用短路求值可以大幅减少逻辑判断的代码量,但同时也会降低代码可读性。
var condition = true;if (condition) { console.log('It is true');}condition && console.log('It is true');if (!condition) { console.log('It is false');}condition || console.log('It is false');
逻辑与(&&
)表达式会返回第一个与 false
相等的值,而逻辑非(||
)表达式会返回第一个与 true
相等的值,都没有则返回最后一个运算数的值。
null && false; // null1 && 2 && 3; // 31 || true; // 10 || false; // false
因为浮点数是不支持位运算的,所以在运算之前会把浮点数的小数部分去掉,也就相当于对浮点数进行了取整。
只要要满足位运算后不改变值的表达式,都可以视作快速取整的一种方式。
|
整数与 0
进行位或者运算时,整数值不变,可用于浮点数取整。取整行为取决于浮点数是正数还是负数,正数时作向下取整,负数时作向上取整。
// 向下取整Math.floor(12.3); // 1212.3|0; // 12// 向上取整Math.ceil(-12.3); // -12-12.3|0; // -12
需要注意位或者运算取整和 Math.floor()
等取整函数在特殊值解决上的差异:
Math.floor(NaN); // NaNNaN|0; // 0Math.floor(Infinity); // InfinityInfinity|0; // 0
~~
运算符~~
运算符利用的就是两次位非运算(~
)后取回原值的特性,取整行为与位或者运算一致。
~~12.3; // 12~~-12.3; // -12
我们通常用取模运算符(%
)来判断奇偶性:
n % 2 === 1 ? 'n是奇数' : 'n是偶数';
当数字转成二进制表达时,判断奇偶性只要要看最后一位是 1
(奇数)还是 0
(偶数),所以我们可以通过与 1
进行按位与运算来判断奇偶性。
1 & 1; // 12 & 1; // 0n & 1 ? 'n是奇数' : 'n是偶数';
**
是 ES7 新添加的幂运算符,详见 tc39提案。
Math.pow(2, 3); // 82**3; // 8
异或者(^
)运算具备这样的性质:
所以通过三次异或者运算可以完成两个整数值(A
、B
)的交换:
var a = 1;var b = 2;a = a ^ b; // 3b = a ^ b; // 1a = a ^ b; // 2
注意,异或者运算不适合于浮点数及其余基本类型的变量交换。
除此之外,利用自反性异或者运算还可以用于整数值的比较:运算结果为0则等值,非0则不等值。
1^1 = 0;1^2 = 3;
void 0
很多 JS 框架、类库都会出现 void 0
这样的写法。void
运算符会对给定的表达式求值并返回 undefined
,所以
void 0 === undefined; // true
用 void 0
来替代 undefined
主要出于两点考虑:
undefined
可以被重写,而 void
作为 JS 的关键字不能被重写;ps:
undefined
在 ES5 中已经是全局对象的一个只读属性,但在局部作用域下仍然能被局部变量覆盖。
undefined = 1;console.log(undefined); // undefined(function() { var undefined = 1; console.log(undefined); // 1})();