# 运算符
运算符用于执行程序代码运算,会针对一个或以上操作数项目来进行运算。
JavaScript中的运算符主要分为:
- 算术运算符
- 关系(比较)运算符
- 赋值运算符
- 逻辑运算符
- 一元运算符
- 三元运算符
- 特殊运算符
- 指数运算符
- 链判断运算符
- Null 判断运算符
- 逻辑赋值运算符
# 算数运算符
JavaScript中的算术运算符中有加(+)、减(-)、乘(*)、除(/)、取余(%)、自增(++)、自减(--)、求幂(**)
# 加法(+)
JavaScript中的+主要用于两个方面,一个是加法运算,另一个是用来进行字符串拼接,加法运算规则如下:
- 数字与除字符串以外类型相加: 将其他类型转化为数字后算术相加,无法转化则结果为NaN
- true 转化为1
- false、null转化为0
- undefined 无法转化
- NaN与除字符串以外类型相加结果都为NaN
- 字符串与任意类型相加: 拼接
1+false //1 '1'+1 //'11' NaN+'1' //'NaN1' [1,2,3]+1 //"1,2,31" {a:2}+'1' // 1
在开发中,我们经常需要将变量的值输出到某个字符串中,这时需要将变量与字符串进行拼接,字符串拼接有两种方式:
# 1. + 拼接
变量必须放到字符串引号外部,变量与字符串之间用+
连接:
var name = "张三", age = 20, sex = "男";
alert( name + "的年龄是:" +age+ ",性别是:" +sex )
# 2. es6模板字符串 (ie不支持)
传统
+
拼接字符串相当繁琐不方便,ES6 引入了模板字符串解决这个问题
模板字符串用 反单引号(`) 标识,可以当作普通字符串使用,或者在字符串中嵌入变量:
var name = "张三", age = 20, sex = "男";
alert( `${name}的年龄是:${age},性别是:${sex}` )
模板字符串特点:
1. 模板字符串中嵌入变量,需要将变量名写在`${}`之中,变量与字符串不需要 `+`连接
2. `${}` 中可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性: `${num + 1}`
3. 模板字符串中可以换行
4. 模板字符串中可以随意使用单双引号
# 减法(-)
- 数字和字符串相减 :
- 字符串全部由数字组成,将字符串转化为数字,再相减
- 字符串不能转化为数字,结束是 NaN
- null转化为0 undefined转化为NaN true为1 false为0
- 字符串和字符串相减 : 和数字和字符串相减规则相同
'11a'-1 //NaN
'11'-1 //10
# 加减法做数字与字符串的转换
- 数字转化为字符串:
num + ""
- 字符串转化为数字:
num - 0
# 乘法运算
- 数字与字符串运算:
- 将字符串尝试着转化为数字,进行运算
- 字符串不能转化为数字,结果是 NaN
- null转化为0 true为1 false为0 空字符串转为0
- Undefined乘所有数据类型的都为NaN
- 字符串和字符串运算 : 和数字和字符串运算规则相同
true*null //0
'11'*'11' // 121
'1a'*22 //NaN
# 除法运算
- 字符串类型 数字类型与 null 相除 结果为 Infinity
- 字符串类型、数字类型 null与 Undefined 相除 结果为 NaN
- 字符串类型 数字类型 null与 字符串类型、数字类型 null相除进行相应转换做除法运算
- 字符串不能转为数字则结果为NaN
- 空字符串转为0
11/null //Infinity
'11'/'11' // 1
'11a'/'11' // NaN
# 取余(%)
取余,即取余数,如 10 % 3
则指 10除以3的余数
用于取一段范围的值
一般不用于小数,因为结果不确定(不精确)。
- Undefined 与所有数据类型的 取余 都为NaN
- 其余数据类型先进行转换,能转为数字则进行取余运算,否则为NaN
''%1 // 0
11%0 // NaN
11%null // NaN
判断数字num是否是偶数:
if(num%2==0){
alert(num + "是偶数")
}
# ++ 自加 -- 自减
规则: i++ 相当于变量i自身值变大1,类似i+=1; i--同理
++
可写在变量前或后:i++
是先访问i然后再自增,而++i
则是先自增然后再访问i的值
var i = 10;
console.log(i++); // 10 先输出,后自增。 console.log(i); i++;
console.log(++i); // 11 先自增,后输出。 i++; console.log(i);
# 求幂运算符
x**y
取x的y次方,同Math.pow(x, y)
3 ** 2 //9
效果同
Math.pow(3, 2) //9
# 关系(比较)运算符
比较运算符得到的结果 都是 boolean
主要有以下几种比较运算符
- >
- <
- >=
- <=
- == (相等)
- != (不相等)
- === (全等)
- !== (不全等)
# 比较规则
- 将比较的对象尝试转化为数字,能转化则按照数字比较,不能转化则为false
NaN
与任意数据比较结果均为 false- 字符串和字符串比较, 比较第一个字符的unicode编码值,第一个字符要是相同,就比较第二个,依次往下(ASCII码表在最末尾)
'10000' < '2' //1的unicode值比2的unicode值小 true '10000' > 2 //转成数字比较 true
==
和全等===
的区别==
是只比较两边的值(如果两边类型不相同,则先尝试着转化,然后再比较,所以耗时比===
多)- 0==undefined (false)
- 0==null (false)
- NaN == NaN (false)
- undefined==null (true)
===
比较两边的值和类型,都相等才返回true;
===
和object.js()
的区别
Object.is(+0,-0); //false
+0===-0 //true
Object.is(NaN,NaN); //true
NaN===NaN //false
# 赋值运算符
=、+=、-=、*=、/=、%=、**=
运算符右边的值赋给左边的变量
运算符 | 实例 | 等价于 |
---|---|---|
= | a=25 | a=25 |
+= | a+=25 | a=a+25 |
-= | a-=25 | a=a-25 |
*= | a*=25 | a=a*25 |
/= | a/=25 | a=a/25 |
%= | a%=25 | a=a%25 |
**= | a**=3 | a=a^3 |
# 逻辑运算符
在JavaScript逻辑运算中,0、""、null、false、undefined、NaN都会判为false,其他都为true
- 与
&&
- 只要有一个是假,结果就是假
- &&左侧是真,结果取右侧; 左侧假,结果取左侧值
- 或
||
- 只要有一个是真,结果就是真
- ||左侧是真,结果取左侧; 左侧假,结果取右侧值
- 非
!
- 取反
- 结果是
boolean
值
总结: 与或运算,哪一侧能决定表达式真假性,则结果取哪一侧。
例:
0 && 1 // 0
0 || 1 // 1
1 && 2 // 2
1 || 2 // 1
!1 // false
!0 // true
# 逻辑运算符的应用:短路原则
与或运算左侧结果已经确定整个表达式真假性,则右侧不再计算
- &&与运算:左侧是假,右侧不进行计算
- ||或运算:左侧是真,右侧不进行计算
# 一元运算符
只能操作一个值的操作符就叫做一元操作符
- new (创建对象) delete (删除对象上的内容)
- typeof -(负号) +(正号)
- instanceof (判断对象是否由一个构造函数实例化)
# 三元运算符
基于某些条件对变量进行赋值的条件运算符,
var iablename=(condition)?value1:value2
condition为true则variablename取:前的值,也就是value1,否则取:后的值,也就是value2
# 三元运算符使用技巧
- 可以简化条件判断
var fee;
if(isMember){
fee="¥2.00";
}else{
fee="¥10.00";
}
fee=isMember ? "¥2.00" : "¥10.00";
- 三元运算符用来执行多个操作,用小括号包裹,再用逗号隔开语句。
# 特殊运算符
- , 逗号 —— 分隔数据
var num1 = 1, num = 2, num3 = 3;
- () 小括号运算符 —— 提升算术优先级
var i = 1 + 3 * 5;
console.log(i); // 16
var l = (1 + 3) * 5;
console.log(l); // 20
# 指数运算符 ES2016
ES2016 新增了一个指数运算符(**)。
2 ** 2 // 4
2 ** 3 // 8
这个运算符的一个特点是右结合,而不是常见的左结合。多个指数运算符连用时,是从最右边开始计算的。
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512
上面代码中,首先计算的是第二个指数运算符,而不是第一个。
指数运算符可以与等号结合,形成一个新的赋值运算符(**=)。
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
# 链判断运算符 ?.
ES2020
编程实务中,如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。比如,读取message.body.user.firstName这个属性,安全的写法是写成下面这样。
// 错误的写法
const firstName = message.body.user.firstName || 'default';
// 正确的写法
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
简化的写法
const firstName = message?.body?.user?.firstName || 'default';
const fooValue = myForm.querySelector('input[name=foo]')?.value
?.
运算符,直接在链式调用的时候判断,左侧的对象是否为null
或undefined
。如果是的,就不再往下运算,而是返回undefined
// 下面是判断对象方法是否存在,如果存在就立即执行的例子。
iterator.return?.()
# Null 判断运算符 ??
ES2020
读取对象属性的时候,如果某个属性的值是null或undefined,有时候需要为它们指定默认值。常见做法是通过||运算符指定默认值。
只要属性的值为null
或undefined
,默认值就会生效,但是属性的值如果为空字符串或false
或0,默认值也会生效
const headerText = response.settings.headerText || 'Hello, world!';
const animationDuration = response.settings.animationDuration || 300;
const showSplashScreen = response.settings.showSplashScreen || true;
Null 判断运算符??
。它的行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值。
const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;
跟链判断运算符?.
配合使用,为null
或undefined
的值设置默认值。
const animationDuration = response.settings?.animationDuration ?? 300;
多个逻辑运算符一起使用,必须用括号表明优先级,否则会报错。
// 报错
lhs && middle ?? rhs
lhs ?? middle && rhs
lhs || middle ?? rhs
lhs ?? middle || rhs
# 逻辑赋值运算符 ES2021
ES2021 引入了三个新的逻辑赋值运算符(logical assignment operators),将逻辑运算符与赋值运算符进行结合。
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)
// 这三个运算符||=、&&=、??=相当于先进行逻辑运算,然后根据运算结果,再视情况进行赋值运算。
它们的一个用途是,为变量或属性设置默认值。
// 老的写法
user.id = user.id || 1;
// 新的写法
user.id ||= 1;
// 老的写法
function example(opts) {
opts.foo = opts.foo ?? 'bar';
opts.baz ?? (opts.baz = 'qux');
}
// 新的写法
function example(opts) {
opts.foo ??= 'bar';
opts.baz ??= 'qux';
}
# 运算符的优先级
下表中的运算符按从最高到最低的优先级列出。具有相同优先级的运算符按从左至右的顺序求值。
运算符 | 运算符类型 |
---|---|
(…) | 圆括号 |
….… , …[…] ,new…(…) ,…(…) | 成员访问,需计算的成员访问,new(带参数列表),函数调用 |
new … | new(无参数列表) |
…++ , …-- | 后置递增(运算符在后) 后置递减(运算符在后) |
!… ,~… ,+… ,-… ,++… ,--… ,typeof… ,void… ,delete… ,await… | 逻辑非 按位非 一元加法 一元减法 前置递增 前置递减 typeof void delete await |
…**… | 幂 |
…*… …/… …%… | 乘法 除法 取余 |
+ - | 加法 减法 |
< <= > >= in instanceof | 小于 小于等于 大于 大于等于 in 判断是否为这个构造函数实例化 |
== != === !== | 等号 非等 全等 非全等 |
&& | 逻辑与 |
¦¦ | 逻辑或 |
… ? … : … | 三元运算符 |
= += -= *= /= %= **= | 赋值 |
, | 逗号 |