- js提供了指数运算符:* 指数运算符:
x ** y
加法运算符
根本规定
- js容许非数值的相加:布尔值主动转化为数值
true + true // 21 + true // 2
- 两个字符串相加,变成连贯运算符
'a' + 'bc' // "abc"
- 字符串+非字符串:非字符串转为字符串,在连贯在一起
1 + 'a' // "1a"false + 'a' // "falsea"
- 运算子的不同,导致了相加和连贯的行为不同,这种景象称为重载。留神,因为从左到右的运算程序,字符串地位不同,运算后果不同
'3' + 4 + 5 // "345"3 + 4 + '5' // "75"
除了加法运算符,其余算术运算符(比方减法、除法和乘法)都不会产生重载。它们的规定是:所有运算子一律转为数值,再进行相应的数学运算。
对象的相加
当运算子为对象时,必须先转换成原始类型的值,而后再相加
var obj = { p: 1 };obj + 2 // "[object Object]2"
对象转换成原始类型的值的规定
- 首先调用对象的
valueOf
办法,返回对象本身
var obj = { p: 1 };obj.valueOf() // { p: 1 }
- 而后调用对象的
toString
办法,将其转为字符串。留神,对象的toString
办法默认返回[object Object]
,所以就失去了最后面那个例子的后果。
var obj = { p: 1 ;}obj.valueOf().toString() // "[object Object]"
失去规定之后,咱们就能够本人定义valueOf
办法或toString
办法,失去想要的后果。
- 自定义valueOf
var obj = { valueOf: function () { return 1; }};obj + 2 // 3
下面代码中,咱们定义obj
对象的valueOf
办法返回1
,于是obj + 2
就失去了3
。这个例子中,因为valueOf
办法间接返回一个原始类型的值,所以不再调用toString
办法。
- 自定义toString
var obj = { toString: function () { return 'hello'; }};obj + 2 // "hello2"
下面代码中,对象obj
的toString
办法返回字符串hello
。后面说过,只有有一个运算子是字符串,加法运算符就变成连贯运算符,返回连贯后的字符串。
- 这里有一个特例,如果运算子是一个
Date
对象的实例,那么会优先执行toString
办法。
var obj = new Date();obj.valueOf = function () { return 1 };obj.toString = function () { return 'hello' };obj + 2 // "hello2"
下面代码中,对象obj
是一个Date
对象的实例,并且自定义了valueOf
办法和toString
办法,后果toString
办法优先执行。
余数运算符
- 运算后果的正负号由第一个运算子正负号决定,不遵循算数法令
-1 % 2 // -11 % -2 // 1
因而,为了失去正数的正确余数值,能够先用绝对值函数
// 谬误的写法function isOdd(n) { return n % 2 === 1;}isOdd(-5) // falseisOdd(-4) // false// 正确的写法function isOdd(n) { return Math.abs(n % 2) === 1;}isOdd(-5) // trueisOdd(-4) // false
数值运算符、负数值运算符
数值运算符(+
)同样应用加号,但它是一元运算符(只须要一个操作数),而加法运算符是二元运算符(须要两个操作数)。
数值运算符的作用在于能够将任何值转为数值(与Number
函数的作用雷同)。
+true // 1+[] // 0+{} // NaN
下面代码示意,非数值通过数值运算符当前,都变成了数值(最初一行NaN
也是数值)。具体的类型转换规定,参见《数据类型转换》一章。
负数值运算符(-
),也同样具备将一个值转为数值的性能,只不过失去的值正负相同。连用两个负数值运算符,等同于数值运算符。
var x = 1;-x // -1-(-x) // 1
下面代码最初一行的圆括号不可少,否则会变成自减运算符。
数值运算符号和负数值运算符,都会返回一个新的值,而不会扭转原始变量的值。
指数运算符
留神,指数运算符是右联合,而不是左联合。即多个指数运算符连用时,先进行最左边的计算。
// 相当于 2 ** (3 ** 2)2 ** 3 ** 2// 512
比拟运算符
比拟运算符能够分为相等比拟和非相等比拟。对于非相等比拟,先看两个运算子是否都是字符串,如果是,就依照字典程序比拟(实际上是比拟 Unicode 码点);否则,将两个运算子都转成数值,再比拟数值的大小
非相等运算符字符串的比拟
若两个都是字符串,依照字典程序进行比拟,即比拟Unicode码点
非相等运算符非字符串的比拟
只有两个运算子有一个不是字符串,就属于非字符串比拟
- 若都是原始类型,(字母、字符串、布尔值)先转换成数值再比拟。这里留神的是,任何值与NaN比拟,返回的都是false(包含NaN自身)
- 对象会先调用
valueOf
办法;如果返回的还是对象,再接着调用toString
办法,最终转换为原始类型的值。在进行比拟
严格相等运算符
严格相等运算符(===)先比拟类型,后比拟值,只有一个不相等就返回false;而相等运算符当类型不同时,会先转换成雷同类型,再比拟
- NaN与任何值都不相等(包含自身),+0=-0
- 复合类型的数据比拟时,不是比拟值是否相等,而是比拟是否指向同一个地址
如果两个变量援用同一个对象,则它们相等。
var v1 = {};var v2 = v1;v1 === v2 // true
留神,对于两个对象的比拟,严格相等运算符比拟的是地址,而大于或小于运算符比拟的是值。
var obj1 = {};var obj2 = {};obj1 > obj2 // falseobj1 < obj2 // falseobj1 === obj2 // false
下面的三个比拟,前两个比拟的是值,最初一个比拟的是地址,所以都返回false
。
- undefined和null与本身严格相等。另外,因为变量申明后默认值为undefined,所以两个只申明未赋值的变量是相等的
var v1;var v2;v1 === v2 // true
相等运算符
- 原始类型的值转换成数值再比拟
- 对象转换成原始函数的值再比拟
- undefined和null互相比拟为true,与其余比拟为false
布尔运算符:将表达式转为布尔值
!取反运算符
除了以下6个值取反后为true,其余都是false:
undefined
null
false
0
NaN
- 空字符串(
''
)
若对一个值间断两次取反运算,等于转为对应的布尔值,与Boolean函数作用雷同,是一种常见的类型转换写法
&&且运算符
运算规定:若第一个为true,则返回第二个的值;若第一个false,间接返回第一个的值,不再对第二个求值
't' && '' // ""'t' && 'f' // "f"'t' && (1 + 2) // 3'' && 'f' // ""'' && '' // ""var x = 1;(1 - 1) && ( x += 1) // 0x // 1
这种跳过第二个运算子的机制,被称为“短路”。有些程序员喜爱用它取代if
构造,比方上面是一段if
构造的代码,就能够用且运算符改写
if (i) { doSomething();}// 等价于i && doSomething();
且运算符能够多个连用,后果会返回第一个为false的值;若所有表达式都为false,则返回最初一个表达式的值
||或运算符
运算规定:
如果第一个运算子的布尔值为true
,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false
,则返回第二个运算子的值。
或运算符能够多个连用,这时返回第一个布尔值为true
的表达式的值。如果所有表达式都为false
,则返回最初一个表达式的值。
或运算符罕用于为一个变量设置默认值。
function saveText(text) { text = text || ''; // ...}// 或者写成saveText(this.text || '')
下面代码示意,如果函数调用时,没有提供参数,则该参数默认设置为空字符串。
二进制运算符
位运算符只对整数起作用,若运算子不是整数,会主动转换为整数后再执行
i = i | 0;
下面这行代码的意思,就是将i
(不论是整数或小数)转为32位整数
二进制或运算符|
- 将小数与0进行二进制或运算,可用于去除小数的小数局部
二进制与运算符&
二进制否运算符~
~ 3 // -4
- 返回后果有时难以了解,因为波及到就三级外部的数值示意机制
3
的32位整数模式是00000000000000000000000000000011
,二进制否运算当前失去11111111111111111111111111111100
。因为第一位(符号位)是1,所以这个数是一个正数。JavaScript 外部采纳补码模式示意正数,即须要将这个数减去1,再取一次反,而后加上负号,能力失去这个正数对应的10进制值。这个数减去1等于11111111111111111111111111111011
,再取一次反失去00000000000000000000000000000100
,再加上负号就是-4
。思考到这样的过程比拟麻烦,能够简略记忆成,一个数与本身的取反值相加,等于-1。
- 对一个整数间断两次二进制否运算,失去自身。对小数间断两次二进制否运算,达到取整成果
- 当对字符串等其余类型的值进行二进制否运算时,js会先调用Number函数,将其转化为数值
异或运算符
- “异或运算”有一个非凡使用,间断对两个数
a
和b
进行三次异或运算,a^=b; b^=a; a^=b;
,能够调换它们的值。这意味着,应用“异或运算”能够在不引入长期变量的前提下,调换两个变量的值。 - 异或运算也能够用来取整。
12.9 ^ 0 // 12
利用:开关作用
位运算符能够用作设置对象属性的开关。
假设某个对象有四个开关,每个开关都是一个变量。那么,能够设置一个四位的二进制数,它的每个位对应一个开关。
var FLAG_A = 1; // 0001var FLAG_B = 2; // 0010var FLAG_C = 4; // 0100var FLAG_D = 8; // 1000
下面代码设置 A、B、C、D 四个开关,每个开关别离占有一个二进制位。
而后,就能够用二进制与运算,查看以后设置是否关上了指定开关。
var flags = 5; // 二进制的0101if (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 = flags & mask;
异或运算能够切换(toggle)以后设置,即第一次执行能够失去以后设置的相同值,再执行一次又失去原来的值。
flags = flags ^ mask;
二进制否运算能够翻转以后设置,即原设置为0
,运算后变为1
;原设置为1
,运算后变为0
。
flags = ~flags;
void运算符
- void运算符的作用是执行一个表达式,而后不返回任何值。
var x = 3;void (x = 5) //undefinedx // 5
- 留神的是,咱们倡议应用void运算符时用圆括号括起来,因为void运算符优先级很高,防止谬误后果。比方,
void 4 + 7
实际上等同于(void 4) + 7
。 - 这个运算符次要用于做浏览器的书签工具,以及在超级链接中插入代码避免页面跳转
<a href="javascript: void(document.form.submit())"> 提交</a>
如上边,用户点击链接提交表单,然而不产生页面跳转
,逗号运算符
- 逗号运算符用于对两个表达式求值,并返回后一个表达式的值
var x = 0;var y = (x++, 10);x // 1y // 10
- 用处:在返回一个值前,进行一些辅助操作
var value = (console.log('Hi!'), true);// Hi!value // true
运算程序
- 留神括号的应用,来防止运算程序与预期不同
- 左联合和右联合。大部分都是左联合,然而赋值运算符、三元运算符和指数运算符是右联合
w = x = y = z;q = a ? b : c ? d : e ? f : g;
w = (x = (y = z));q = a ? b : (c ? d : (e ? f : g));
2 ** 3 ** 2// 相当于 2 ** (3 ** 2)// 512