我是小又又,住在武汉,做了两年新媒体,准备用 6 个月时间转行前端。
今日学习目标
昨天基于一些页面搜索,学习了《JavaScirpt 高级程序设计》(第三版) 第 3 章节中的 ES 基础概念中 String 数据类型的很多方法和属性,发现其实还是有很多基础知识点需要补充学习。 所以,今天主要是基于搜索来仔细学习 第 3 章节中的 3.5 操作符,又是适合学习的一天,加油,小又又!!!!
一元操作符
递增操作符
基础说明
递增运算符为其操作数增加1,返回一个数值。
- 如果使用后置(postfix),即运算符位于操作数的后面(如 x++),那么将会在递增前返回数值。
- 如果使用前置(prefix),即运算符位于操作数的前面(如 ++x),那么将会在递增后返回数值。
语法
运算符: x++ 或者 ++x
示例
// 后置
var x = 3;
y = x++;
// y = 3, x = 4
// 前置
var a = 2;
b = ++a;
// a = 3, b = 3
注意事项
递增运算符不仅应用于数字值,还可以用于字符串、布尔值、浮点值和对象,在应用于不同的值时,递增操作符会遵循下列规则。
- 在应用于一个包含有效数字字符的字符串时,会先将其转换为数字值,将字符串变量变成数值变量,再执行加一的操作。
- 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN,将字符串变量变成数值变量。
- 在应用于布尔值 false 时,先将其转换为 0,将布尔值变量变成数值变量 ,再执行加一的操作。
- 在应用于布尔值 true 时,先将其转换为 1,将布尔值变量变成数值变量 ,再执行加一的操作。
- 在应用于浮点数值时,执行加一的操作。
- 在应用于对象时,先调用对象的 valueOf() 方法,以取得一个可供操作的值。然后对该值应用前述规则,如果转换之后的值是 NaN ,则再调用 toString() 方法后,再应用前述规则,将对象变量变成数值变量。
var s1 = "2";
var s2 = "z";
var b1 = false;
var b2 = true;
var f = 1.1;
var o = {
valueOf: function(){
return -1;
}
};
s1++;// 3
s2++;// NaN
b1++;// 1
b2++;// 2
f++;// 2.1
o++;// 0
递减操作符
基础说明
递减运算符将其操作数减去1,并返回一个数值。
- 如果后置使用(如 x--),则在递减前返回数值。
- 如果前置使用(如 --x),则在递减后返回数值。
语法
运算符: x-- or --x
示例
// 后置
var x = 3;
y = x--; // y = 3, x = 2
// 前置
var a = 2;
b = --a; // a = 1, b = 1
注意事项
递减运算符不仅应用于数字值,还可以用于字符串、布尔值、浮点值和对象,在应用于不同的值时,和上面递增操作符会遵循同样规则。
var s1 = "2";
var s2 = "z";
var b1 = false;
var b2 = true;
var f = 1.1;
var o = {
valueOf: function(){
return -1;
}
};
s1--;// 1
s2--;// NaN
b1--;// -2
b2--;// -1
f--;// 0.10000000000000009
o--;// -2
一元加和减操作符
基础说明
绝大多数开发人员对一元加减都不会陌生,而且这两个 ECMAScript 操作符的作用与数学书上讲的完全一样。 主要是在具体数值前添加 + 或者 - 操作符。
- 加号(+)放在数值前面,对数值不会产生任何影响。
- 减号(-)放在数值前面,表示数值是一个负数。
主要用于基础的算术运算,也会应用于数据类型转换。
语法
运算符: x-- or --x
示例
var s1 = "2";
var s2 = "z";
var b1 = false;
var b2 = true;
var f = 1.1;
var o = {
valueOf: function(){
return -1;
}
};
s1 = +s1;// 2
s2 = -s2;// NaN
b1 = +b1;// 0
b2 = -b2;// -1
f = +f;// 1.1
o = -o;// 1
注意事项
一元正号运算符位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转换成一个数值。
尽管一元负号也能转换非数值类型,但是一元正号是转换其他对象到数值的最快方法,也是最推荐的做法,因为它不会对数值执行任何多余操作。它可以将字符串转换成整数和浮点数形式,也可以转换非字符串值 true
,false
和
null
。
小数和十六进制格式字符串也可以转换成数值。负数形式字符串也可以转换成数值(对于十六进制不适用)。如果它不能解析一个值,则计算结果为 NaN。
位操作符
基础说明
按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值。
例如,十进制数9,用二进制表示则为1001。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。
运算符 | 用法 | 描述 |
---|---|---|
按位与( AND) | a & b |
对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。 |
按位或(OR) | a | b |
对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。 |
按位异或(XOR) | a ^ b |
对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。 |
按位非(NOT) | ~ a |
反转操作数的比特位,即0变成1,1变成0。 |
左移(L) | a << b |
将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。 |
有符号右移 | a >> b |
将 a 的二进制表示向右移b (< 32) 位,丢弃被移出的位。 |
无符号右移 | a >>> b |
将 a 的二进制表示向右移b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。 |
有符号32位整数
所有的按位操作符的操作数都会被转成补码(two's complement)形式的有符号32位整数。 补码形式是指一个数的负对应值(negative counterpart)(如 5和-5)为数值的所有比特位反转后,再加1。反转比特位即该数值进行非位运算,也即该数值的反码。
补码保证了当一个数是正数时,其最左的比特位是0,当一个数是负数时,其最左的比特位是1。因此,最左边的比特位被称为符号位(sign bit)。
0
是所有比特数字0组成的整数。
0 (base 10) = 00000000000000000000000000000000 (base 2)
-1
是所有比特数字1组成的整数。
-1 (base 10) = 11111111111111111111111111111111 (base 2)
从概念上讲,按位逻辑操作符按遵守下面规则
- 操作数被转换成32位整数,用比特序列(0和1组成)表示。超过32位的数字会被丢弃。例如, 以下具有32位以上的整数将转换为32位整数
转换前: 11100110111110100000000000000110000000000001
转换后: 10100000000000000110000000000001
- 第一个操作数的每个比特位与第二个操作数的相应比特位匹配:第一位对应第一位,第二位对应第二位,以此类推。
- 位运算符应用到每对比特位,结果是新的比特值。
按位非(NOT)
对每一个比特位执行非(NOT)操作。NOT a
结果为 a 的反转(即反码)。
非操作的真值表
a | NOT a |
---|---|
0 | 1 |
1 | 0 |
9 (base 10) = 00000000000000000000000000001001 (base 2)
--------------------------------
~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
对任一数值 x 进行按位非操作的结果为 -(x + 1)。例如,~5 结果为 -6。
与 indexOf 一起使用示例
var str = 'rawr';
var searchFor = 'a';
// 这是 if (-1*str.indexOf('a') <= 0) 条件判断的另一种方法
if (~str.indexOf(searchFor)) {
// searchFor 包含在字符串中
} else {
// searchFor 不包含在字符串中
}
// (~str.indexOf(searchFor))的返回值
// r == -1
// a == -2
// w == -3
按位与(AND)
对每对比特位执行与(AND)操作。只有 a 和 b 都是 1 时,a AND b 才是 1。与操作的真值表如下
a | b | a AND b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
将任一数值 x 与 0 执行按位与操作,其结果都为 0。将任一数值 x 与 -1 执行按位与操作,其结果都为 x。
按位或(OR)
对每一对比特位执行或(OR)操作。如果 a 或 b 为 1,则 a
OR b
结果为 1。
或操作的真值表:
a | b | a OR b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)
将任一数值 x 与 0 进行按位或操作,其结果都是 x。将任一数值 x 与 -1 进行按位或操作,其结果都为 -1。 补充一些例子
1 | 0 ; // 1
1.1 | 0 ; // 1
'asfdasfda' | 0 ; // 0
0 | 0 ; // 0
(-1) | 0 ; // -1
(-1.5646) | 0 ; // -1
[] | 0 ; // 0
({}) | 0 ; // 0
"123456" | 0 ; // 123456
1.23E2 | 0; // 123
1.23E12 | 0; // 1639353344
-1.23E2 | 0; // -123
-1.23E12 | 0; // -1639353344
按位异或(XOR)
对每一对比特位执行异或(XOR)操作。当 a 和 b 不相同时,a
XOR b
的结果为 1。异或操作真值表:
a | b | a XOR b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)
将任一数值 x 与 0 进行异或操作,其结果为 x。将任一数值 x 与 -1 进行异或操作,其结果为 ~x。
左移
该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。
举例, 9 << 2
yields 36
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)
在数字 x 上左移 y 比特得到 x * 2.
有符号的右移
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。
由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。
例如, 9 >> 2
得到 2
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
相比之下, -9 >> 2
得到 -3,因为符号被保留了。
-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)
无符号的右移
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。
因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)
对于非负数,有符号右移和无符号右移总是返回相同的结果。
例如 9 >>> 2
和 9 >> 2
一样返回 2
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
但是对于负数却不尽相同。 -9 >>> 2
产生 1073741821 这和 -9 >> 2
不同
-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
综合案例
例子:标志位与掩码
位运算经常被用来创建、处理以及读取标志位序列——一种类似二进制的变量。虽然可以使用变量代替标志位序列,但是这样可以节省内存(1/32)。 例如,有 4 个标志位
- 标志位 A:我们有 ant
- 标志位 B:我们有 bat
- 标志位 C:我们有 cat
- 标志位 D:我们有 duck
标志位通过位序列 DCBA 来表示。
- 当一个位被置位 (set) 时,它的值为 1 。
- 当被清除 (clear) 时,它的值为 0 。
例如一个变量 flags
的二进制值为 0101
var flags = 5; // 二进制 0101
这个值表示:
- 标志位 A 是 true (我们有 ant);
- 标志位 B 是 false (我们没有 bat);
- 标志位 C 是 true (我们有 cat);
- 标志位 D 是 false (我们没有 duck);
因为位运算是 32 位的, 0101 实际上是 00000000000000000000000000000101。因为前面多余的 0 没有任何意义,所以他们可以被忽略。
**掩码 (bitmask) **是一个通过与/或来读取标志位的位序列。 典型的定义每个标志位的原语掩码如下
var FLAG_A = 1; // 0001
var FLAG_B = 2; // 0010
var FLAG_C = 4; // 0100
var FLAG_D = 8; // 1000
新的掩码可以在以上掩码上使用逻辑运算创建。 例如,掩码 1011 可以通过 FLAG_A、FLAG_B 和 FLAG_D 逻辑或得到:
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
某个特定的位可以通过与掩码做逻辑与运算得到,通过与掩码的与运算可以去掉无关的位,得到特定的位。 例如,掩码 0100 可以用来检查标志位 C 是否被置位
// 如果我们有 cat
if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true
// do stuff
}
一个有多个位被置位的掩码表达任一/或者的含义。 例如,以下两个表达是等价的
// 如果我们有 bat 或者 cat 至少一个
// (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true
if ((flags & FLAG_B) || (flags & FLAG_C)) {
// do stuff
}
// 如果我们有 bat 或者 cat 至少一个
var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110
if (flags & mask) { // 0101 & 0110 => 0100 => true
// do stuff
}
可以通过与掩码做或运算设置标志位,掩码中为 1 的位可以设置对应的位。 例如掩码 1100 可用来设置位 C 和 D
// 我们有 cat 和 duck
var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100
flags |= mask; // 0101 | 1100 => 1101
可以通过与掩码做与运算清除标志位,掩码中为 0 的位可以设置对应的位。 掩码可以通过对原语掩码做非运算得到。 例如,掩码 1010 可以用来清除标志位 A 和 C
// 我们没有 ant 也没有 cat
var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010
flags &= mask; // 1101 & 1010 => 1000
如上的掩码同样可以通过 ~FLAG_A & ~FLAG_C
得到(德摩根定律)
// 我们没有 ant 也没有 cat
var mask = ~FLAG_A & ~FLAG_C;
flags &= mask; // 1101 & 1010 => 1000
标志位可以使用异或运算切换。所有值为 1 的位可以切换对应的位。 例如,掩码 0110 可以用来切换标志位 B 和 C:
// 如果我们以前没有 bat ,那么我们现在有 bat
// 但是如果我们已经有了一个,那么现在没有了
// 对 cat 也是相同的情况
var mask = FLAG_B | FLAG_C;
flags = flags ^ mask; // 1100 ^ 0110 => 1010
最后,所有标志位可以通过非运算翻转
// entering parallel universe...
flags = ~flags; // ~1010 => 0101
转换片段
将一个二进制数的 [String](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String)
转换为十进制的 [Number](https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Number)
:
var sBinString = "1011";
var nMyNumber = parseInt(sBinString, 2);
alert(nMyNumber); // 打印 11
var nMyNumber = 11;
var sBinString = nMyNumber.toString(2);
alert(sBinString); // 打印 1011
自动化掩码创建
如果你需要从一系列的 Boolean
值创建一个掩码,你可以
function createMask () {
var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length;
for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++);
return nMask;
}
var mask1 = createMask(true, true, false, true); // 11, i.e.: 1011
var mask2 = createMask(false, false, true); // 4, i.e.: 0100
var mask3 = createMask(true); // 1, i.e.: 0001
// etc.
alert(mask1); // 打印 11
逆算法:从掩码得到布尔数组
function arrayFromMask (nMask) {
// nMask 必须介于 -2147483648 和 2147483647 之间
if (nMask > 0x7fffffff || nMask < -0x80000000) {
throw new TypeError("arrayFromMask - out of range");
}
for (var nShifted = nMask, aFromMask = []; nShifted;
aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1);
return aFromMask;
}
var array1 = arrayFromMask(11);
var array2 = arrayFromMask(4);
var array3 = arrayFromMask(1);
alert("[" + array1.join(", ") + "]");
// 打印 "[true, true, false, true]", i.e.: 11, i.e.: 1011
你可以同时测试以上两个算法……
var nTest = 19; // our custom mask
var nResult = createMask.apply(this, arrayFromMask(nTest));
alert(nResult); // 19
仅仅由于教学目的 (因为有 Number.toString(2)
方法),我们展示如何修改 arrayFromMask 算法通过 Number 返回二进制的 String,而非 Boolean Array
function createBinaryString (nMask) {
// nMask must be between -2147483648 and 2147483647
for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
return sMask;
}
var string1 = createBinaryString(11);// 00000000000000000000000000001011
var string2 = createBinaryString(4);// 00000000000000000000000000000100
var string3 = createBinaryString(1);// 00000000000000000000000000000001
布尔操作符
基础描述
逻辑运算符通常用于布尔
型(逻辑)值。这种情况下,它们返回一个布尔值。然而,&&
和 ||
运算符会返回一个指定操作数的值,因此,这些运算符也用于非布尔值。这时,它们也就会返回一个非布尔型值。
逻辑运算符如下表所示 (其中_expr_
可能是任何一种类型, 不一定是布尔值):
运算符 | 语法 | 说明 |
---|---|---|
逻辑与,AND(&& ) |
_expr1_ && _expr2_ |
若 expr**1** 可转换为 true ,则返回 expr**2** ;否则,返回 expr**1** 。 |
逻辑或,OR(|| ) |
_expr1_ || _expr2_ |
若 expr**1** 可转换为 true ,则返回 expr**1** ;否则,返回 expr**2** 。 |
逻辑非,NOT(! ) |
!_expr_ |
若 expr 可转换为 true ,则返回 false ;否则,返回 true 。 |
如果一个值可以被转换为 true
,那么这个值就是所谓的 truthy,如果可以被转换为 false
,那么这个值就是所谓的 falsy。
会被转换为 false
的表达式有:
null
;NaN
;0
;- 空字符串(
""
or''
or ````); undefined
。
尽管 &&
和 ||
运算符能够使用非布尔值的操作数, 但它们依然可以被看作是布尔操作符,因为它们的返回值总是能够被转换为布尔值。如果要显式地将它们的返回值(或者表达式)转换为布尔值,请使用双重非运算符(即!!
)或者 Boolean 构造函数。
逻辑非
下面的代码是 !
(逻辑非) 运算符的示例
n1 = !true // !t 返回 false
n2 = !false // !f 返回 true
n3 = !'' // !f 返回 true
n4 = !'Cat' // !t 返回 false
双重非(!!
)运算符
可能使用双重非运算符的一个场景,是显式地将任意值强制转换为其对应的 布尔值。这种转换是基于被转换值的 "truthyness" 和 "falsyness"的。同样的转换可以通过 Boolean 函数完成。
n1 = !!true // !!truthy 返回 true
n2 = !!{} // !!truthy 返回 true: 任何 对象都是 truthy 的…
n3 = !!(new Boolean(false)) // …甚至 .valueOf() 返回 false 的布尔值对象也是!
n4 = !!false // !!falsy 返回 false
n5 = !!"" // !!falsy 返回 false
n6 = !!Boolean(false) // !!falsy 返回 false
逻辑与
下面的代码是 && (逻辑与) 运算符的示例
a1 = true && true // t && t 返回 true
a2 = true && false // t && f 返回 false
a3 = false && true // f && t 返回 false
a4 = false && (3 == 4) // f && f 返回 false
a5 = "Cat" && "Dog" // t && t 返回 "Dog"
a6 = false && "Cat" // f && t 返回 false
a7 = "Cat" && false // t && f 返回 false
a8 = '' && false // f && f 返回 ""
a9 = false && '' // f && f 返回 false
逻辑或
下面的代码是 || (逻辑或) 运算符的示例。
o1 = true || true // t || t 返回 true
o2 = false || true // f || t 返回 true
o3 = true || false // t || f 返回 true
o4 = false || (3 == 4) // f || f 返回 false
o5 = "Cat" || "Dog" // t || t 返回 "Cat"
o6 = false || "Cat" // f || t 返回 "Cat"
o7 = "Cat" || false // t || f 返回 "Cat"
o8 = '' || false // f || f 返回 false
o9 = false || '' // f || f 返回 ""
短路计算
由于逻辑表达式的运算顺序是从左到右,也可以用以下规则进行"短路"计算:
(some falsy expression) && (_expr)_
短路计算的结果为假。(some truthy expression) || _(expr)_
短路计算的结果为真。
短路意味着上述表达式中的expr部分不会被执行,因此expr的任何副作用都不会生效(举个例子,如果expr是一次函数调用,这次调用就不会发生)。造成这种现象的原因是,整个表达式的值在第一个操作数被计算后已经确定了。 看一个例子:
function A(){ console.log('called A'); return false; }
function B(){ console.log('called B'); return true; }
console.log( A() && B() );
// logs "called A" due to the function call,
// then logs false (which is the resulting value of the operator)
console.log( B() || A() );
// logs "called B" due to the function call,
// then logs true (which is the resulting value of the operator)
操作符优先级
请注意,由于运算符优先级
的存在,下面的表达式的结果却不相同。右侧被小括号括起来的操作变成了独立的表达式。
false && true || true // 结果为 true
false && (true || true) // 结果为 false
综合案例
逻辑操作符之间是可以进行相关转换的~~~~
转换方向 | 转换前 | 转换后 |
---|---|---|
将 AND 转换为 OR | bCondition1 && bCondition2 | !(!bCondition1 |
将 OR 转换为 AND | bCondition1 || bCondition2 | !(!bCondition1 && !bCondition2) |
删除嵌套的 AND | bCondition1 || (bCondition2 && bCondition3) | bCondition1 |
删除嵌套的 OR | bCondition1 && (bCondition2 |
乘性操作符
乘法
基础说明
乘法运算符的结果是操作数的乘积。
语法
运算符: x * y
示例
2 * 2 // 4
-2 * 2 // -4
Infinity * 0 // NaN
Infinity * Infinity // Infinity
"foo" * 2 // NaN
除法
基础说明
除法运算符的结果是操作数的商 ,左操作数是被除数,右操作数是除数。
语法
运算符: x / y
示例
1 / 2 // 在 JavaScript 中返回 0.5
1 / 2 // 在 Java 中返回 0
// (不需要数字是明确的浮点数)
1.0 / 2.0 // 在 JavaScript 或 Java 中都返回 0.5
2.0 / 0 // 在 JavaScript 中返回 Infinity
2.0 / 0.0 // 同样返回 Infinity
2.0 / -0.0 // 在 JavaScript 中返回 -Infinity
求模
基础说明
求余运算符返回第一个操作数对第二个操作数的模,即 var1
对 var2
取模,其中 var1
和 var2
是变量。取模功能就是 var1
除以 var2
的整型余数。
语法
运算符: var1 % var2
示例
12 % 5 // 2
-1 % 2 // -1
NaN % 2 // NaN
1 % 2 // 1
2 % 3 // 2
-4 % 2 // -0
5.5 % 2 // 1.5
幂
基础说明
幂运算符返回第一个操作数做底数,第二个操作数做指数的乘方。即,var1``var2
,其中 var1
和 var2
是其两个操作数。幂运算符是右结合的。a ** b ** c
等同于 a ** (b ** c)
。
语法
运算符: var1 ** var2
示例
2 ** 3 // 8
3 ** 2 // 9
3 ** 2.5 // 15.588457268119896
10 ** -1 // 0.1
NaN ** 2 // NaN
2 ** 3 ** 2 // 512
2 ** (3 ** 2) // 512
(2 ** 3) ** 2 // 64
// 如果要反转求幂表达式结果的符号,你可以采用这样的方式
-(2 ** 2) // -4
// 强制求幂表达式的基数为负数
(-2) ** 2 // 4
注意事项
包括 PHP 或 Python 等的大多数语言中,都包含幂运算符(一般来说符号是 ^ 或者 **
)。这些语言中的幂运算符有着比其他的单目运算符(如一元 + 或一元 - )更高的优先级。
但是作为例外,在 Bash 中, **
运算符被设计为比单目运算符优先级更低。在最新的 JavaScript(ES2016) 中,禁止使用带歧义的幂运算表达式。
比如,底数前不能紧跟一元运算符(+/-/~/!/delete/void/typeof
)。
-2 ** 2;
// Illegal expression. Wrap left hand side or entire exponentiation in parentheses.
// 在 Bash 中等于 4 ,而在其他语言中一般等于 -4
// 在 JavaScript 中是错误的,因为这会有歧义
-(2 ** 2);
// -4 在 JavaScript 中能够明显体现出作者的意图
加性操作符
加法
基础说明
加法运算符的作用是数值求和,或者字符串拼接。
语法
运算符: x + y
示例
// Number + Number -> 数字相加
1 + 2 // 3
// Boolean + Number -> 数字相加
true + 1 // 2
// Boolean + Boolean -> 数字相加
false + false // 0
// Number + String -> 字符串连接
5 + "foo" // "5foo"
// String + Boolean -> 字符串连接
"foo" + false // "foofalse"
// String + String -> 字符串连接
"foo" + "bar" // "foobar"
减法
基础说明
减法运算符使两个操作数相减,结果是它们的差值。
语法
运算符: x - y
示例
5 - 3 // 2
3 - 5 // -2
"foo" - 3 // NaN
关系操作符
大于运算符 (>)
大于运算符仅当左操作数大于右操作数时返回 true
语法
x > y
例子
4 > 3 // true
大于等于运算符 (>=)
大于等于运算符当左操作数大于或等于右操作数时返回 true
语法
x >= y
例子
4 >= 3 // true
3 >= 3 // true
小于运算符 (<)
小于运算符仅当左操作数小于右操作数时返回true
语法
x < y
例子
3 < 4 // true
小于等于运算符 (<=)
小于等于运算符当左操作数小于或等于右操作数时返回true
语法
x <= y
例子
3 <= 4 // true
等式操作符
相等操作符
基础说明
比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。
当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
x == y
使用案例
1 == 1 // true
"1" == 1 // true
1 == '1' // true
0 == false // true
不相等操作符
基础说明
不等操作符仅当操作数不相等时返回true,如果两操作数不是同一类型,JavaScript会尝试将其转为一个合适的类型,然后进行比较。
如果两操作数为对象类型,JavaScript会比较其内部引用地址,仅当他们在内存中引用不同对象时不相等。
x != y
使用案例
1 != 2 // true
1 != "1" // false
1 != '1' // false
1 != true // false
0 != false // false
严格相等操作符
基础说明
一致运算符不会进行类型转换,仅当操作数严格相等时返回true
x === y
使用案例
3 === 3 // true
3 === '3' // false
var object1 = {"value":"key"}, object2={"value":"key"};
object1 === object2 //false
严格不相等操作符
基础说明
不一致运算符当操作数不相等或不同类型时返回true
x !== y
使用案例
3 !== '3' // true
4 !== 3 // true
条件操作符
基础说明
条件(三元)运算符是 JavaScript 仅有的使用三个操作数的运算符。一个条件后面会跟一个问号(?),如果条件为 truthy ,则问号后面的表达式A将会执行;表达式A后面跟着一个冒号(:),如果条件为 falsy ,则冒号后面的表达式B将会执行。本运算符经常作为 if
语句的简捷形式来使用。
condition ? exprIfTrue : exprIfFalse
参数
condition
计算结果用作条件的表达式exprIfTrue
如果表达式condition
的计算结果是 truthy(它和true
相等或者可以转换成true
),那么表达式exprIfTrue
将会被求值。exprIfFalse
如果表达式condition
的计算结果是 falsy(它可以转换成false
),那么表达式exprIfFalse
将会被执行。
使用案例
除了 false
,可能的假值表达式还有:null
、NaN
、 0
、空字符串( ""
)、和 undefined
。如果 condition
是以上中的任何一个, 那么条件表达式的结果就是 exprIfFalse
表达式执行的结果。
一个简单的例子:
var age = 26;
var beverage = (age >= 21) ? "Beer" : "Juice";
console.log(beverage); // "Beer"
一个常见的用法是处理可能为
null
的值:
function greeting(person) {
var name = person ? person.name : "stranger";
return "Howdy, " + name;
}
console.log(greeting({name: 'Alice'})); // "Howdy, Alice"
console.log(greeting(null)); // "Howdy, stranger"
赋值操作符
基础说明
赋值运算符(assignment operator)基于右值(right operand)的值,给左值(left operand)赋值。
简单的赋值运算符,把一个值赋给一个变量。为了把一个值赋给多个变量,可以以链式使用赋值运算符。
Operator: x = y
使用案例
// Assuming the following variables
x = 5
y = 10
z = 25
x = y // x is 10
x = y = z // x, y and z are all 25
组合说明
每个主要算术操作符,以及个别的其他操作符,都有对应的复合赋值操作符
基本的赋值运算符是等号(=
),该运算符把它右边的运算值赋给左边。即,x = y
把 y
的值赋给 x
。 其他的赋值运算符通常是标准运算符的简写形式,如下面的定义与示例。
名称 | 简写形式 | 含义 |
---|---|---|
赋值(Assignment) | x = y |
x = y |
加赋值(Addition assignment) | x += y |
x = x + y |
减赋值(Subtraction assignment) | x -= y |
x = x - y |
乘赋值(Multiplication assigment | x *= y |
x = x * y |
除赋值(Division assignment) | x /= y |
x = x / y |
模赋值(Remainder assignment) | x %= y |
x = x % y |
指数赋值(Exponentiation assignment) | x **= y |
x = x ** y |
左移赋值(Left shift assignment) | x <<= y |
x = x << y |
右移赋值(Right shift assignment) | x >>= y |
x = x >> y |
无符号右移赋值(Unsigned right shift assignment) | x >>>= y |
x = x >>> y |
按位与赋值(Bitwise AND assignment) | x &= y |
x = x & y |
按位异或赋值(Bitwise XOR assignment) | x ^= y |
x = x ^ y |
按位或赋值(Bitwise OR assignment) | x |= y |
x = x | y |
逗号操作符
基础说明
逗号操作符 对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
语法
expr1, expr2, expr3...
参数
expr1, expr2, expr3...
任一表达式。
当你想要在期望一个表达式的位置包含多个表达式时,可以使用逗号操作符。
使用案例
for 循环
假设 a
是一个二维数组,每一维度包含10个元素,则下面的代码使用逗号操作符一次递增/递减两个变量。需要注意的是,var
语句中的逗号_不是_逗号操作符,因为它不是存在于一个表达式中。尽管从实际效果来看,那个逗号同逗号运算符的表现很相似。
但确切地说,它是 var
语句中的一个特殊符号,用于把多个变量声明结合成一个。下面的代码打印一个二维数组中斜线方向的元素
for (var i = 0, j = 9; i <= 9; i++, j--)
document.writeln("a[" + i + "][" + j + "] = " + a[i][j]);
处理后返回
另一个使用逗号操作符的例子是在返回值前处理一些操作。 如同下面的代码,只有最后一个表达式被返回,其他的都只是被求值。
function myFunc () {
var x = 0;
return (x += 1, x); // the same of return ++x;
}
运算符优先级
今日学习总结
今日心情
今日主要是基于搜索来仔细学习 第 3 章节中的 3.5 操作符,感受到操作符组合的厉害之处~~~,感觉很不错,看了一下 MDN 发现其实还有很多操作符,但是,书上没有写,就暂时没有学习,希望明天学习到更多东西~~~~
最近文章发布一直提示Request Entity Too Large
,改了好多版,才发成功,好麻烦~~~
本文使用 mdnice 排版