javaScript提供了以下算术运算符:
减法,乘法,除法运算就是正常的数学计算,这里不做详细讲解。
加法运算符(+
),用来求两个运算子的和。但是JavaScript中,允许非数值相加,而且涉及到字符串时,加法运算符会变成连接运算符。
// 正常的数值相加
1 + 1; // 2
// 非数值相加,布尔值会自动转换为数值,然后进行加法运算
true + true ; // 2
false + false; // 0
true + false; // 1
1 + true; // 2
1 + false; // 1
// 运算子有字符串时,变为连接运算符
"hello " + "world!"; // "hello world!"
1 + "a"; // "1a"
true + "a"; // "truea"
加法运算符是在运行时决定,到底是执行相加,还是执行连接。这种现象称为“重载”。
// 加法运算的重载
1 + 1 + "a"; // "2a"
"a" + 1 + 1; // "a11"
如果运算子是对象,必须先转成原始类型的值,然后再相加。
var x = { name: "jidi" };
x + 2 // "[object Object]2"
对象转换为原始类型的值,规则如下:
valueOf
方法(一般情况下,对象的valueOf
方法总是返回对象自身)。toString
方法(对象的toString
方法默认返回[Object,Object])。上面那个例子,实际上可以看成是:
var x = { name: "jidi" };
var y = x.valueOf(); // {name: "jidi"}
var z = y.toString(); // "[object Object]"
z + 2; // "[object Object]2"
我们可以自己定义valueOf
和toString
方法。以得到想要的结果。
// 自定义valueOf方法
var x = {
name: "jidi",
valueOf: function(){
return 5;
}
};
// 自定义toString方法
var y = {
name: "jidi",
toString: function(){
return 10;
}
}
5 + x; // 10
5 + y; // 15
注意:如果参与加法运算的两个运算子,其中有一个是Date
对象实例,会先执行toStrnig
方法。
var now = new Date();
now.valueOf = function(){
return 5;
}
now.toString = function(){
return 10;
}
5 + now; // 15
余数运算符(%
)返回前一个运算子被后一个运算子除,所得的余数。余数运算的结果的正负号由第一个运算子决定。
12 % 5; // 2
// 余数运算结果正负情况由第一个运算子正负情况决定
-12 % 5; // -2
-12 % -5; // -2
自增和自减运算符,是一元运算符,只需要一个运算子。它们的作用是将运算子首先转为数值,然后加上1或者减去1。它们会修改原始变量。
var x = 1;
++x // 2
x // 2
--x // 1
x // 1
自增和自减是仅有的两个具有运算副作用(参与运算后,变量的值发生改变)的运算符。
自增和自减运算符又分为前置和后置两种:前置自增(自减),会先进行自增(自减),然后返回变量操作后的值;后置自增(自减)会先返回变量操作之前的值,然后再进行自增(自减)操作。
var x = 1;
var y = 1;
x++ // 1
++y // 2
数值运算符(+
)是一元运算符,可以将任何数值转为数值。
负数值运算符(-
)也是一元运算符,可以将任何数值转为数值,只是结果值正负相反。
var x = 1;
// 正数值运算符
+x; // 1
+true; // 1
+[]; // 0
// 负数值运算符
-x; // -1
-true; // -1
指数运算符(**
)是二元运算符,前一个运算子是底数,后一个运算子是指数。指数运算是右结合。
5 ** 2; // 25
// 指数运算的右结合
// 相当于5 ** (2 ** 2)
5 ** 2 ** 2; // 625
赋值运算符用于给变量赋值。但是赋值运算符可以与其他运算符结合,形成变体。
// 普通赋值运算符
var x = 2; // 将数值2赋值给变量x
var y = x; // 将变量x赋值给变量y
// 与其他运算符结合使用
x += 2; // 等价于 x = x + 2;
x -= 2; // 等价于 x = x - 2;
x *= 2; // 等价于 x = x * 2;
x /= 2; // 等价于 x = x / 2;
x %= 2; // 等价于 x = x % 2;
x **= 2; // 等价于 x = x ** 2;
比较运算符用来比较两个值的大小,返回一个布尔值。
JavaScript中提供了以下比较运算符:
>
,大于运算符<
,小于运算符>=
,大于等于运算符<=
,小于等于运算符==
,等于运算符===
,严格相等运算符!=
,不相等运算符!==
,严格不相等运算符上述运算符可以分为两类:相等比较运算符与非相等比较运算符,两者规则不一样。
对于非相等运算符,如果运算子都是字符串,则是按照字典顺序进行比较。JavaScript引擎会首先比较首字符的Unicode码点,如果相等,则比较第二个字符的Unicode码点,以此类推…
"this".charCodeAt(); // 首字符Unicode码点为116
"is".charCodeAt(); // 首字符Unicode码点为105
"this" > "is"; // 116>105,true
"This".charCodeAt(); // 首字符Unicode码点为84
"this">"This"; // true
如果两个运算子中至少有一个不是字符串,则存在以下情况:
(1) 原始类型值
如果两个运算子都为原始类型值,则先转换成数值,然后再进行比较。但是任何值与NaN
比较,返回值都为false
。
4 > "3"; // true
2 > true; // true
1 < false; // false
1 > null; // true
2 > NaN // false
1 <= NaN // false
'1' > NaN // false
'1' <= NaN // false
NaN > NaN // false
NaN <= NaN // false
注意:underfined
转换为数值会转换成为NaN
,即任何值与underfined
和NaN
进行比较,结果都是false
。
(2) 对象
如果运算子是对象,则会转换成为原始类型的值,然后再进行比较。
对象转换为原始类型的值按照以下步骤进行的:
valueOf
方法(对象调用valueOf
方法一般返回对象自身),如果返回原始类型的值,不再进行后续步骤。valueOf
方法结果仍旧是对象,则调用toString
方法(对象的toString方法默认返回[Object,Object])。var x = [2];
x.valueOf(); // [2]
x.valueOf().toString(); // "2"
x > "11" // true ,等同于 [2].valueOf().toString() > "11",即"2">“11”
// 改写valueOf方法
x.valueOf = function () { return "1" };
x > "11" // false,等同于 [2].valueOf() > "11",即 "1" > "11"
上述例子中,数组x
调用valueOf
方法返回x
本身,然后调用toString
方法,返回"2"
,此时是"2"
与"11"
两个字符串之间进行比较,比较的是 Unicode
码点位置。
严格相等运算符(===
)是二元运算符,比较的是两个运算子是否为同一个值。参与运算的运算子情况不同,具有不同的结果:
false
。true
,否则返回false
。true
,否则返回false
。null
与underfined
与自身严格相等。// 两个运算子值类型不同,直接返回false
1 === "1"; // false
true === "true"; // false
true === 1; // false
"1"===new String("1"); // false
// 两个运算子值类型相同,且为原始数据类型,值相等就返回true
true === true; // true
1 === 1; // true
"a" === "a"; // true
// 两个运算子为复合数据类型,比较的是地址是否一样
{} === {} // false
[] === [] // false
var x = new String("a");
y = x;
x === y // true
// 特殊值 nul,undefined与自身严格相等
null === null;
undefined === undefined ;
严格不相等运算符(!==
),它的算法就是先求严格相等运算符(===
)的结果,然后返回相反值。
true !== "true"; // true,等价于 !(true === "true")
相等运算符(==
)是二元运算符,用来比较时,会进行数据类型转换。 参与运算的运算子情况不同,也具有不同的结果:
null
,NaN
与undefined
。// 数据类型一致,与严格相等运算符一样
1 == 1; // true
true == true; // true
{} == {} // false
[] == [] // false
// 数据类型不一致
// 都是原始数据类型,先转换为数值再进行比较
1 == true; // true
0 == false; // true
1 == "1"; // true
'' == 0; // true
'' == false; // true
// 对象与原始数据类型比较,对象会先转为原始数据类型然后再进行比较
var person = {
name: "jidi",
sex: "男",
valueOf: function(){
return 1;
},
toString: function(){
return "jidi";
}
}
//对象与数值比较,对象转换为数值然后进行比较
person == 1; // true
person.valueOf = function(){return {}};// 自定义valueOf方法返回一个空对象
// 对象与字符串比较,对象转换为字符串然后进行比较
person == "jidi"; // true
// 对象与布尔值比较,对象与布尔值都转换为数值然后进行比较
[1] == true; // true
[] == false; // true
// 特殊值null,NaN,undefined
// NaN与任何值(包括本身),都为false
NaN == true; // false
NaN == 1; // false
NaN == null; //false
NaN == undefined; // false
NaN == NaN; // false
NaN == ""; // false
//null与undefined与其他值进行比较时,都会false,只有相互比较或者自身比较时返回true
null == 0;
null == false;
null == "null";
null == "";
null == null;
undefined == 0;
undefined == "0";
undefined == "";
undefined == "undefined";
undefined == false;
undefined == undefined;
null == undefined;
注意:由于相等运算符(==
)会进行数据类型转换,可能会出现一些违反常理的结果:
"" == 0; // true
false == "0"; // true
5 == true; // false
5 == false; // false
相等运算符(==
)有一个对应的“不相等运算符”(!=
),它的算法就是先求相等运算符的结果,然后返回相反值。
布尔值运算符用于将表达式转为布尔值,一共有四个运算符。
!
,取反运算符&&
,且运算符||
,或运算符?:
,三元运算符取反运算符用于将布尔值变成相反值,即原来为true
取反后变为false
,原来为false
取反后为true
。
对于非布尔值,取反运算符会将其转换为布尔值。
!true; // false
!false; // true
// 非布尔值取反
!undefined // true
!null // true
!0 // true
!NaN // true
!"" // true
![] // false
!{} // false
数据类型转换的时候,以下几个值对它们进行取反为true
,其它的值取反都为false
。
且运算符(&&
)是二元运算符。且运算符(&&
)的运算规则:如果第一个运算子布尔值为true
,返回第二个运算子的值;如果第一个运算子布尔值为false
,直接返回第一个运算子的值,且不再对第二个运算子进行求值,即会出现短路现象。
true && false; // false
5 > 3 && 200; // 200
var x = 1;
23>12 && x++; //2, x=2
false && true; // false
3>5 && 200; // false
var y = 20;
// 发生短路现象
0 && y--; // 0,y=20
且运算符(&&
)可以多个连用,此时返回第一个布尔值为false
的表达式的值;如果表达式的布尔值都为true
,则返回最后一个表达式的值。
// 返回第一个布尔值为false的表达式的值
1 && true && null && "example"; // null
1 && 0 && null && "example"; // 0
//表达式布尔值全为true,返回最后一个表达式的值
1 && true && 23 && "example"; // "example"
或运算符(||
) 也是二元运算符。或运算符(||
)的运算规则:第一个运算子的布尔值为true
,则返回第一个运算子的值,且不会对第二个运算子进行计算,即发生短路现象;如果第一个运算子的布尔值为false
,则返回第二个运算子的值。
1 || 2; // 1
//发生短路
var x = 3;
3 > 2 || x++; // true,x=3
3 < 2 || x++; // 4,x=4
利用或运算符(||
) 的短路现象,可以给函数参数设置默认值。
function f(x){
x = x || 5; // 如果x没有传值,则默认x=5
return x;
}
// 调用函数
f(); // 此时返回默认值5
或运算符(||
) 可以多个连用,这时返回第一个布尔值为true
的表达式的值。如果所有表达式都为false
,则返回最后一个表达式的值。
// 返回第一个布尔值为true的表达式的值
false || 0 || '' || 4 || 'foo' || true; // 4
// 所有表达式的布尔值为false,返回最后一个表达式的值
false || 0 || '' || null; // null
三元运算符是JavaScript唯一一个需要三个运算子的运算符。三元运算符的规则是:如果第一个运算子的布尔值为true
,返回第二个运算子的值,否则返回第三个运算子的值。
true ? 1 : 2; // 1
false ? 1 : 2; // 2
JavaScript中提供了以下位运算符:
|
,二进制或运算符&
,二进制与运算符~
,二进制否运算符^
,异或运算符<<
,左移运算符>>
,右移运算符>>>
,头部补零的右移运算符位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。另外,在 JavaScript 内部,数值是以64位浮点数的形式储存的,但是在参与位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。
二进制或运算符(|
),逐位比较运算子,两个二进制位中只要有一个为1
,就返回1
,否则返回0
。
0 | 4; // 4
上面例子中,0
和4
的的二进制形式分别为:000
和100
(只截取了部分,完整的是一个32位的二进制数字),二进制或运算结果为:100
,即4。
小数参与位运算时,小数部分会舍去,只保留整数部分参与位运算。所以二进制或运算的一个常用场景是小数取整。
// 定义一个函数,获得整数部分的值
function getIntNumber(x){
return x | 0;
}
// 调用该函数
getIntNumber(2.3); // 2
getIntNumber(-2.9); // 2
二进制与运算符(&
),逐位比较两个运算子,两个二进制位之中只要有一个位为0
,就返回0
,否则返回1
。
2 & 3; // 1
二进制否运算符(~
)将每个二进制位都变为相反值(0
变为1
,1
变为0
)。
~ 2; // -3
从上面例子看到,一个整数进行二进制否运算,结果并不是简单的改变值正负情况,这是因为计算机内部是使用补码来存储负数的。负数按位取反然后加1
就得到补码。
简单的记法就是,一个数与自身的取反值相加等于-1
。
异或运算符(^
)在两个二进制位不同时返回1
,相同时返回0
。
0 ^ 3; // 3
上述代码中,0
和3
的二进制表示为00
和11
,异或的结果为11
,即为3。
我曾经碰到过一个面试题,在不引入新变量的前提下,交换变量a
,b
的值。在这里就可以用异或解决。
var a = 3;
var b = 4;
a ^= b;
b ^= a;
a ^= b;
a; // 4
b; // 3
左移运算符(<<
)表示将一个数的二进制值向左移动指定的位数,尾部以0
填充,向左移动的时候,最高位的符号位是一起移动的。左移n
位,相当于乘以2
的n
次方。
如果左移0
位,就相当于将数值转为32
位整数,也可以取的一个数的整数部分。
右移运算符(>>
)表示将一个数的二进制值向右移动指定的位数。如果是正数,头部全部补0
;如果是负数,头部全部补1
。
头部补零的右移运算符(>>>
)与右移运算符(>>
)只有一个差别,就是一个数的二进制形式向右移动时,头部一律补零,而不考虑符号位。
void
运算符的作用是执行一个表达式,返回undefined
。
void(7 +7 ); // undefined
void
运算符可以在超链接中插入代码但是不会发生网页跳转。
<a href="javascript: void(document.form.submit())">
提交
</a>
逗号运算符(,
)用于对两个表达式求值,并返回后一个表达式的值。
"x", "y"; // "y"
var x = 0;
var y = (x++, 10);
x // 1
y // 10
本博客是自己学习笔记,原文请参考JavaScript教程。
如有问题,请及时指出!
欢迎沟通交流,邮箱:[email protected]。