# JS 部分运算符操作

\[TOC]

## 1. 关于对象的运算符操作

如果运算子是对象可以定义对象的`valueOf` 属性为函数，实际运算中通过调用该函数获取对象的实际值，在实际调用是`obj.valueOf().toString()` 返回一个对象的值。

```javascript
> obj.valueOf = () => {return 12;}
[Function]
> obj
{ valueOf: [Function] }
> obj.valueOf()
12
> obj + 1
13
> obj > 1
true
> obj === '12'
false
> obj === 12
false
> obj == 12
true
> obj + 'test'
'12test'
> '' + obj
'12'
> '0' + obj
'012'
```

## 2. 严格相等比较

俗语严格相等比较时，如果两个值的类型不同，直接返回false，不会进行类型转化；对于同一类型的原始类型的值比较，相等则返回true；对于复合类型的数据进行比较，不是比较是否相等而是比较是否为同一地址，**注意对于对象的比较，严格比较运算符比较的是地址，大于，小于比较的是对象的数值** **对于三个特殊值：undefined null 与自身严格相等 NaN 与任何值严格比较均不等**

```javascript
> 1 === 0x1
true
> NaN === NaN
false
> [] === []
false
> {} === {}
false
```

## 3. 二进制运算符

JS中一共有7个二进制位运算符，直接处理每一个bit。需要注意的是位运算符只对整数起作用，虽然JS中所有数字都是以64位浮点数进行存储的，但是进行位运算时，是用32位带符号位的整数进行运算的，返回值也是一个32位的带符号整数。使用位运算符会有较好的性能。

可以使用`|` 运算符将任意数转换为32位整数,使用二进制运算符处理小数时，会将小数部分舍去，只处理整数部分

```javascript
function toInt(a) {
    return a | 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

0 & 12  // 0
```

**否运算符～：**

否运算符会将所有32位整数的每一位都取反，注意数字是以补码表示，所以对于3取反后`00000000000000000000011` 变为 `111111111111111111111100` ,补码表示的-4，取反值与原值相加为-1

对于非数字类型进行取反，会默认调用`Number()` 函数，先转化为数字,对于NaN null undefined 取反均为-1

```javascript
> ~~109
109
> ~47.12
-48
> ~'011'
-12
> ~'0110'
-111


> ~'12 va'
-1
> Number('12 vds')
NaN
> ~[]
-1
> ~NaN
-1
> ~null
-1
```

**带符号位的右移**

js支持基本的左移运算以及右移运算,也可以进行带符号位的右移,即进行右移操作时符号位也参与移动,头部补0,所以进行该运算时得到的额结果一定为正

**位运算符可以用作设置对象属性的开关**

假定某个对象有四个开关，每个开关都是一个变量。那么，可以设置一个四位的二进制数，它的每个位对应一个开关。

```
var FLAG_A = 1; // 0001
var FLAG_B = 2; // 0010
var FLAG_C = 4; // 0100
var FLAG_D = 8; // 1000
```

上面代码设置 A、B、C、D 四个开关，每个开关分别占有一个二进制位。

然后，就可以用二进制与运算检验，当前设置是否打开了指定开关。

```
var flags = 5; // 二进制的0101

if (flags & FLAG_C) {
  // ...
}
// 0101 & 0100 => 0100 => true
```

上面代码检验是否打开了开关`C`。如果打开，会返回`true`，否则返回`false`。

现在假设需要打开`A`、`B`、`D`三个开关，我们可以构造一个掩码变量。

```
var mask = FLAG_A | FLAG_B | FLAG_D;
// 0001 | 0010 | 1000 => 1011
```

上面代码对`A`、`B`、`D`三个变量进行二进制或运算，得到掩码值为二进制的`1011`。

有了掩码，二进制或运算可以确保打开指定的开关。

```
flags = flags | mask;
```

二进制与运算可以将当前设置中凡是与开关设置不一样的项，全部关闭。

```
flags = flags & mask;
```

异或运算可以切换（toggle）当前设置，即第一次执行可以得到当前设置的相反值，再执行一次又得到原来的值。

```
flags = flags ^ mask;
```

二进制否运算可以翻转当前设置，即原设置为`0`，运算后变为`1`；原设置为`1`，运算后变为`0`。

```
flags = ~flags;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://books.innohub.top/webinfo/js-operators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
