本文介绍了,js运算符的知识。包括js中的表达式、运算符的分类、运算符的优先级、运算符的结合性、运算符的运算顺序等知识。
前提知识-表达式
表达式是一组代码的集合,它返回一个值。
原始表达式
原始表达式是表达式的最小单位,它不再包含其他表达式。
常量(变量的一种,一般是全大写字母的形式)、变量、直接量、关键字。1
2
3
4
5
6COUNT // 常量
i // 变量
123 // 数字直接量
'hello' // 字符串直接量
/pattern/ // 正则表达式直接量
null // 关键字
初始化表达式
1 | [1,2,3] // 数组初始化表达式 |
函数定义表达式
1 | var = function add(x,y){ |
属性访问表达式
1 | arr.length; |
函数调用表达式
函数调用表达式以一个函数表达式开始,这个函数表达式指代了要调用的函数。函数表达式后跟随一对圆括号,括号内是一个以逗号隔开的参数列表。
先计算函数表达式,再计算参数表达式。1
add(1,2);
对象创建表达式
1 | new Object(); |
运算符的分类
赋值运算符
1 | var a = 1; //赋值 |
相等运算符
等于
- 当两边操作数类型相同时,按全等规则判断。
- 当两边操作数类型不同时,先进行隐式类型转换,规则如下:
- undefined和null相等,undefined、null和其他任何类型都不相等。
- 如果有一个操作数是数字类型或布尔类型,则把另一个操作数转为数字类型在进行比较。
- 如果有一个操作数是对象,另一个操作数是原始类型值,先把对象转为原始类型值,先调用valueOf方法,如果返回值为原始类型,则按照以上的规则比较,否则再继续调用toString方法转为原始类型值。日期对象会先调用toString方法。
1 | undefined == null; // true |
大牛的总结:相等运算符
全等
- 当两边操作数类型不同时,返回false。
当两边操作数类型相同时,原始类型比较的是值,对象类型比较的是引用地址。相同返回true,不同返回false。NaN不等任何数值,包括它本身。注意,当两个操作数都是字符串时,比较的是字符串的编码。
比较运算符
比较运算符包括:大于运算符,小于运算符,大于等于运算符,小于等于运算符
数值的比较,两个操作数都是数值,有一个操作数为数值,把另一个操作数转为数值。
- 字符串的比较,即字符串编码的比较,两个操作数都是字符串。
- 如果操作数是引用类型,现将操作数转为原始类型值,先调用valueOf方法,如果返回原始值,则按照上面两跳规则进行判断,否则继续调用toString方法,然后再按照上面的规则进行判断。
乘性运算符
乘性运算符包括:乘法运算符,除法运算符,求模运算符
运算规则为,将操作数转为数字再进行计算。不能转为数值时,返回NaN。
逻辑与和逻辑或
逻辑与
返回值为运行到哪个操作数的返回值。如果第一个操作数为true,返回值为第二个操作数的返回值。如果第一个操作数为false,返回值为第一个操作数的返回值。
- 对两个布尔值进行运算,如果其中有一个为false则返回值为false,如果两个值都为true则返回值为true。
- 对两个表达式进行运算,如果其中有一个为false则返回值为false,如果两个值都为true则返回值为true。一般用在判断语句中,两个表达式的返回值都为布尔值。
- 对两个表达式进行运算,如果第一个表达式返回true,则运行第二个表达式,否则不运行第二个表达式。短路写法,一般第一个表达式为判断条件,第二个表达式是一个执行操作。
1
2
3
4
5
6
7
8// 应用在判断语句中
var a = 10;
var b = 20;
if(a > 0 && b < 50){
console.log('逻辑与')
}
// 短路写法,第一个操作数返回true,运行第二个操作数
fn && fn();
逻辑或
返回值为运行到哪个操作数的返回值。如果第一个操作数为false,返回值为第二个操作数的返回值。如果第一个操作数为true,返回值为第一个操作数的返回值。
- 对两个布尔值进行运算,如果有一个为true返回值为true,如果两个都为false返回值为false。
- 对两个表达式进行运算,如果有一个表达式返回true则返回值为true,如果两个表达式都返回false则返回值为false
- 对两个表达式进行运算,如果第一个表达式返回false,则运行第二个表达式,否则不运行第二个表达值。短路写法,用于赋值操作,一般第一个表达式为判断条件,第二个表达式是一个执行操作。
1
2
3
4
5
6
7
8// 应用在判断语句中
var a = 10;
var b = 20;
if(a > 0 || b > 50){
console.log('逻辑或')
}
// 短路写法,第一个操作数返回false,进行赋值
obj.age && obj.age = 18;
条件运算符
condition ? expression1 : expression1
当条件为true时,运算符会返回表达式1的值,当条件为false时,运算符会返回表达式2的值。
结合性为从左向右运算。
逗号运算符
逗号运算符对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
是优先级最低的运算符。
加性运算符
加法运算符
- 如果有一个操作数是字符串类型,另一个操作数是原始类型值,将另一个操作数转为字符串,然后进行字符串拼接。
- 如果两个操作数都是原始类型值且不是字符串类型,则将操作数转为数值,然后进行数值的相加。
- 如果有一个操作数是字符串类型,另一个操作数是复杂类型值,先将另一个操作数转为原始类型值(先调用valueOf方法,不是原始值再调用toString方法),如果不是字符串类型,然后再转为字符串,进行字符串拼接。
- 如果一个操作数是数字类型,另一个操作数是除了字符串之外的原始类型值,就将操作数转为数字,然后进行数字的相加。
- 如果一个或两个操作数是复杂类型值,就将操作数转为原始值(先调用valueOf方法,不是原始值再调用toString方法),然后再按照上面的规则进行字符串拼接或数字的相加。
减法运算符
将两个操作数都转为数字然后进行相减。其中复杂类型值先转为原始值(先调用valueOf方法,不是原始值再调用toString方法),然后再转为数字。
一元运算符
只能操作一个表达式的运算符叫做一元运算符。
一元加运算符
将后面的操作数转为数字类型,和使用Number方法效果相同,返回数字或NaN。
- 原始类型值
- 数字:返回数字本身,包括负数也是返回其本身
- 字符串:空字符串转为0,数字字符串转为对应的数值,其他转为NaN
- null:转为0
- undefined:转为NaN
- 布尔值:true转为1,false转为0
- 引用类型值
- 先调用vlaueOf方法,如果返回值是原始类型值,按照原始类型值的规则进行转换,如果不是原始类型值,再继续调用toString方法,得到原始类型值,再按照原始类型值的规则进行转换。
一元减
- 数字:返回数字对应的负数
- 其他:先将操作数转为数字(即进行和一元加一样的操作),再返回数值对应的负数。
递增和递减(有副作用)
把所有的操作数转为数字类型,然后进行加1或减1的操作。
- 前置:先进行加或减,再进行运算
- 后置:先进行运算,再进行加或减
逻辑非
把操作数转为布尔类型,然后再取反。
按位非
操作数是数字时,运算效果是,对操作数取负值,然后减1。
typeof
typeof返回操作数的类型。可以对操作数使用括号包裹,用以表示优先级。
返回值为字符串。包括’number’,’boolean’,’null’,’undefined’,’string’,’object’。
void
对给定的表达式进行求值,然后返回undefined
delete(有副作用)
用于删除对象的某个属性。成功删除时返回true,否则返回false。
- 如果试图删除的属性不存在,那么将不起作用,但任然返回true。
- 只会删除对象上自身属性,不会删除原型链上的属性
- 使用var、let、const声明的变量不能被删除,返回false。直接声明的变量可以被删除,因为这个变量是全局对象的属性。
- 使用definedProperty方法设置为不可配置的属性不能删除。
运算符的优先级
属性访问的优先级最高,其次是一元运算符,再次是乘性运算符,再次是加性运算符,再次是比较运算符,再次是相等运算符,再次是逻辑或和逻辑与,再次是条件运算符,再次是赋值运算符,再次是逗号运算符。
运算符的结合性
在运算符优先级相同的情况下,运算的先后顺序。
一元运算符、三目运算、赋值运算符是右结合的其他都是左结合。
运算顺序
运算符的优先级和结合性规定了,它们在复杂表达式中的运算顺序。但并没有规定子表达式的计算过程中的运算顺序。js总是严格按照从左至右的顺序来计算表达式。
复杂类型值的toString和valueOf的执行顺序
- 复杂类型值转为字符串时,先调用toString,返回值不为原始类型值时,继续调用valueOf,得到原始类型值,再转为字符串类型,如果还得不到原始类型值则会报错
- 复杂类型值转为数值时,先调用valueOf,返回值不为原始类型值时,继续调用toString,得到原始类型值,再转为数值类型,如果还得不到原始类型值则会报错
- 复杂类型值转为原始类型值时,先调用valueOf,返回值不为原始类型值时,继续调用toString,如果还得不到原始类型值则会报错
- 日期对象转为原始类型值时,先调用toString
1
2
3
4
5
6
7
8
9
10
11var obj = {
valueOf: function(){return 10},
toString: function(){return 'abc'}
}
var newObj = {
valueOf: function(){return 10},
toString: function(){return 'abc'}
}
alert(obj); // 返回'abc',相当于转为字符串
console.log(String(obj)) // 返回'abc',相当于转为字符串
console.log('' + obj) // 转为原始值