运算符

原文链接

1 算术运算符

1.1 加法运算符

加法运算符是在运行时决定,到底是执行相加,还是执行连接,这种现象称为重载。

'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"

除了加法运算符,其他算术运算符(比如减法、除法和乘法)都不会发生重载,所有运算子一律转为数值。

对象 obj 转成原始类型的值是 [object Object]

var obj = { p: 1 };
obj.valueOf().toString() // "[object Object]"

知道了这个规则以后,就可以自己定义 valueOf 方法或 toString 方法,得到想要的结果。当 valueOf 方法直接返回一个原始类型的值时,不再调用 toString 方法。

var obj = {
  valueOf: function () {
    return 1;
  }
};
obj + 2 // 3

var obj = {
  toString: function () {
    return 'hello';
  }
};
obj + 2 // "hello2"

有一个特例: Date 对象的实例优先执行 toString 方法。

var obj = new Date();
obj.valueOf = function () { return 1 };
obj.toString = function () { return 'hello' };

obj + 2 // "hello2"

1.2 余数运算符

余数运算结果的正负号由第一个运算子的正负号决定。

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

为了得到负数的正确余数值,需要借助绝对值函数。

// 错误的写法
function isOdd(n) {
  return n % 2 === 1;
}
isOdd(-5) // false
isOdd(-4) // false

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

1.3 数值运算符

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

var x = 1;
-x // -1
-(-x) // 1

1.4 指数运算符

注意,指数运算符是右结合,而不是左结合,多个指数运算符连用时,先进行最右边的计算。

// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512

2 比较运算符

2.1 正常比较

字符串直接通过 Unicode 的比较。原始类型转成数值后比较。对象通过 valueOf 和 toString 转成原始类型后比较。

'cat' > 'dog' // false
'cat' > 'catalog' // false

2.2 严格比较

JavaScript 提供两种相等运算符: ===== 。简单说,它们的区别是相等运算符比较两个值是否相等,严格相等运算符比较它们是否为“同一个值”。如果两个值不是同一类型,严格相等运算符直接返回false,而相等运算符会将它们转换成同一个类型,再用严格相等运算符进行比较。

不相等运算符 !=!== 是对应相等运算符的取反操作。

3 布尔运算符

  • 取反运算符 !
  • 且运算符 &&
  • 或运算符 ||
  • 三元运算符 ?:
!undefined // true
!null // true
!0 // true
!NaN // true
!"" // true

!54 // false
!'hello' // false
![] // false
!{} // false

4 位运算符

  • 否运算符 ~
  • 且运算符 &
  • 或运算符 |
  • 异或运算符 ^
  • 左移运算符 <<
  • 右移运算符 >>
  • 头部补零右移运算符 >>>

注意,位运算符只对整数起作用,虽然在 JavaScript 内部,数值都是以 64 位浮点数的形式储存,但是做位运算的时候,是以 32 位带符号的整数进行运算的,并且返回值也是一个 32 位带符号的整数。将任意数值转为 32 位整数的函数如下:

function toInt32(x) {
  return x | 0;
}

toInt32(1.001) // 1
toInt32(1.999) // 1
toInt32(1) // 1
toInt32(-1) // -1
toInt32(Math.pow(2, 32) + 1) // 1
toInt32(Math.pow(2, 32) - 1) // -1

多坑,待考。

头部补零右移运算符与右移运算符只有一个差别,就是头部一律补零,不考虑符号位,所以该运算总是得到正值。

位运算常常用作开关。

5 空运算符

空运算符的作用是执行一个表达式,返回 undefined 。有两种写法,建议总是使用括号。

void 0 // undefined
void(0) // undefined

空运算符的主要用途是浏览器书签和在超级链接中插入代码防止网页跳转。

<script>
function f() {
  console.log('Hello World');
}
</script>
<a href="http://example.com" onclick="f(); return false;">点击</a>

上面代码中,点击链接后,会先执行 onclick 的代码,由于 onclick 返回 false ,所以浏览器不会跳转到 example.com 。如果用空运算符改写,返回 undefined ,同样不会跳转,连虚拟网址都省了。

<script>
function f() {
  console.log('Hello World');
}
</script>
<a href="javascript: void(f())">文字</a>

6 逗号运算符

逗号运算符用于在返回一个值之前进行一些辅助操作,它返回的是后一个表达式的值。

7 运算顺序

那么多运算符,你记不住的,也没有必要记住,老老实实加括号吧。