JS高程笔记 2

Keywords: Bitwise+Operators Logical+Operators

Bitwise Operators

Bitwise NOT (~)

很简单,就是二进制里每一位 0 ⇆ 1 。

var num1 = 25;             // binary 00000000000000000000000000011001 
var num2 = ~num1;          // binary 11111111111111111111111111100110 
alert(num2);               // -26

但是我们会发现,~ 并不相当于直接取其相反数对应的二进制,而是比相反数还小 1 。
也就是说,~ 在十进制里相当于:

var num1 = 25;
var num2 = -num1 - 1;
alert(num2);                // -26

虽然两者得到一样的结果,因为 bitwise operators 更贴近底层的原因,但是 ~ 执行起来更快。

Bitwise AND (&)

根据真值表,& 只有当两位都是 1 的时候才返回 1。

alert(25 & 3);              // 1
  25 = 0000 0000 0000 0000 0000 0000 0001 1001
   3 = 0000 0000 0000 0000 0000 0000 0000 0011
 ---------------------------------------------
 AND = 0000 0000 0000 0000 0000 0000 0000 0001

Bitwise OR (|)

两位中任意一位是 1 就返回 1 。

alert(25 | 3);              // 27
 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
 --------------------------------------------
 OR = 0000 0000 0000 0000 0000 0000 0001 1011

Bitwise XOR (^)

两位中只有一位是 1 才返回 1 。

alert(25 ^ 3);              // 26
  25 = 0000 0000 0000 0000 0000 0000 0001 1001
   3 = 0000 0000 0000 0000 0000 0000 0000 0011
 ---------------------------------------------
 XOR = 0000 0000 0000 0000 0000 0000 0001 1010

Left Shift (<<)

所有位左移指定的位数。

num1 =  2
num2 = -2
alert(num1 << 9);           // 1024
alert(num2 << 5);           // -64
num1      = 0000 0000 0000 0000 0000 0000 0000 0010 (binary) =    2 (decimal)
num1 << 9 = 0000 0000 0000 0000 0000 0100 0000 0000 (binary) = 1024 (decimal)
num2      = 1111 1111 1111 1111 1111 1111 1111 1110 (binary) =   -2 (decimal)
num2 << 5 = 1111 1111 1111 1111 1111 1111 1100 0000 (binary) =  -64 (decimal)

Signed Right Shift (>>)

符号位保留原样,其它位右移指定的位数。

64 >> 5 = 2                 // 就把上面的例子倒过来就好啦,(偷懒…)

Unsigned Right Shift (>>>)

所有位右移指定的位数,包括符号位。

var oldValue = -64;              //equal to binary 1111 1111 1111 1111 1111 1111 1100 00000
var newValue = oldValue >>> 5;   //equal to decimal 134217726, binary 0000 0111 1111 1111 1111 1111 1111 1110

奇特的现象,-64 biang 的一下变成了134217726。

Boolean Operators

在介绍具体的 operators 之前,还是先介绍一下常见的值对应的布尔值。
获取一个值的Boolean有几种方法,比如:Boolean() (function), new Boolean (object)(不推荐), !!。

// ture
Boolean(1234);          // 除 0 外的任意数
Boolean('Tada!');
Boolean('0');
Boolean(new Object);    // "object"
Boolean(Boolean);       // "function"

// false
Boolean(0);
Boolean('');            // 空字符串
Boolean(null);
Boolean(undefined);
Boolean(NaN);

说起通过new Booolean来获取布尔值为啥不推荐,引用MDN:

Any object of which the value is not undefined or null, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement.

Do not use a Boolean object to convert a non-boolean value to a boolean value. Instead, use Boolean as a function to perform this task.

(任何值不为 undefined或者 null的对象, 包括值为false的Boolean对象, 在条件语句中,其值都将作为true来判断。不要通过新建Boolean对象的方法来将一个非布尔值转化成布尔值. 直接使用Boolean函数才是正确的。)

用new Boolean,可能会导致意想不到的结果:

var x = new Boolean(false);         // Boolean {[[PrimitiveValue]]: false}
if (x) {
    // this code is executed 这里的代码仍会执行,因为 x 是一个Object, Boolean(x) === true
}

var y = Boolean(false);
if (y) {
    // this code is not executed 这里的代码不会被执行
}

Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object.

(不要将原始值true false,和值为true false的Boolean对象相混淆。)

Logical NOT (!)

这个运算符总是返回布尔值(跟接下来要讲到的几个别的运算符不同)。

! 运算符先将运算对象转换成其对应的布尔值,然后返回其相反的布尔值。

!false;                 // true
!Boolean(true);         // false

! 还可以用来将非布尔值转换成布尔值,只需要将两个 ! 置于变量之前就可以啦~

第一个 ! ,无论何种数据类型,将会返回一个布尔值;

第二个 ! ,返回其相反的布尔值,所以两个 !! 就会返回真实的布尔值啦~

Logical AND (&&)

与 & (Bitwise AND) 长得很像的 && (Logical AND)。( ´▽` *)

&& 也可以用在所有类型的值上,不仅仅是 Boolean 型。类似的,也只有当两个值对应的布尔值都为true时才返回true。

如果第一个运算对象是 Object,然后将会返回第二个运算对象。

如果第二个运算对象是 Object,只有第一个运算对象是 true 时,(第二个运算对象)才会被返回。

如果两者中任意一值是 null, undefined, NaN,则会相应地返回 null, undefined, NaN。

let o = new Object;
o && 233;               // 233
false && o;             // false
o && o;                 // Object
233 && null;            // null

&& 存在着逻辑短路现象,如果第一个运算对象能决定着返回的结果(比如在Logical AND 中,第一个运算结果是 false),那么将不会对第二个运算对象求值。毕竟只要第一个是 false,那么无论第二个的取值是个啥东东,结果都不可能是 true,也就没必要对第二个运算对象求值了。

var found = true;
var result = (found && someUndeclaredVariable);     //error occurs here
alert(result);                                      //this line never executes

var found = false;
var result = (found && someUndeclaredVariable);     //no error
alert(result);                                      //works

Logical OR (||)

| (Bitwise OR) 的远房亲戚 || (Logical OR)。( *´▽` )

类似的,两个值中只要有一个为 true 就会返回 true。

如果第一个运算对象是 Object,它就会返回自己啦~

如果第一个运算对象的值是 false,那么将会返回第二个运算对象 (ATTENTION)。

如果两个值都是 null 或 undefined 或 NaN,则会相应地返回 null 或 undefined 或 NaN。

同样的,在 || 中也存在短路。

var found = true;
var result = (found || someUndeclaredVariable);     // no error
alert(result);                                      // works

var found = false;
var result = (found || someUndeclaredVariable);     // error occurs here
alert(result);                                      // this line never executes

利用这个特性,我们可以避免将 null, undefined, NaN 赋值给一个变量,这种模式在 JS 中经常用到 (ATTENTION)。

var myObject = preferredObject || backupObject;

preferredObject, backupObject两者之一将被赋值给 myObject,如果 preferredObject 有效,那自然prefer啦;但是假如 preferredObject 无效,这时候就需要 backupObject 来救场啦,不管表演如何,咱们总不要把这场子冷下来嘛,你说是吧~

Multiplicative Operators

Multiply (*)

基本都与从小到大的数学课上老师念叨的东西一致。

值得注意的几点:

  • 计算的结果超出了范围 → ±Infinity
  • 两者之一是 NaN → NaN
  • Infinity 0 → NaN
  • ±Infinity 非零的数 → ±Infinity
  • ±Infinity * ±Infinity → ±Infinity

运算对象不是数字,别担心,我有妙全自动Number()!

'233' * '233' = 54289

Devide (/)

也差不多,小学老师教得好。
同样,看一下几点特殊的地方:

  • 计算的结果超出了范围 → ±Infinity
  • 两者之一是 NaN → NaN
  • 0 / 0 → NaN
  • 非零数 / 0 → ±Infinity (按极限来理解)
  • Infinity / ±(finity) → ±Infinity

运算对象不是数字,别担心,我有*猛先森Number()!

'233' / '233' = 1

Modulus (%)

  • Infinity % (finity) → NaN
  • (finity) % 0 → NaN (乘,除,求余0都是NaN)
  • Infinity % Infinity → NaN
  • (finity) % Infinity → dividend
  • 0 % nonzero → 0
  • Additive Operators

Add (+)

  • Infinity + Infinity → Infinity
  • -Infinity + -Infinity → -Infinity
  • Infinity + -Infinity → NaN
  • +0 + +0 = +0
  • -0 + -0 = -0
  • -0 + +0 = +0

对于字符串:

'Am a' + 'string' = 'Am a string'
2 + '33' = '233'
true + '233' = 'true233'

ATTENTION: 最常见的错误之一

var num1 = 5;
var num2 = 10;
var message = 'The sum of 5 and 10 is ' + num1 + num2;
alert(message);    // "The sum of 5 and 10 is 510"

结果的 message 并不是我们预期的 “The sum of 5 and 10 is 15”

产生这样的结果是因为:每一个值的相加是分离的。

字符串 “The sum of 5 and 10 is “ 先加上自动转换成字符串的 “5”,结果已变成了 “The sum of 5 and 10 is 5”,后面的 10 也是类似的处理。所以结果会跟我们的预期有出入。

解决起来很简单,只需要:

var message = 'The sum of 5 and 10 is ' + (num1 + num2)
alert(message);     // "The sum of 5 and 10 is 15"

改变一下执行的顺序。

This blog is under a CC BY-NC-SA 4.0 Unported License
Link to this article: http://nhh.ink/2017/04/05/professional-javascript-2/