JS中的运算符

本文章版权归饥人谷_Lyndon和饥人谷所有,转载请注明出处。

运算符是数据处理的基础,能够从现有数据中获得新的数据。JS中的运算符种类可以分为如下六类:

  1. 算术运算符
  2. 赋值运算符
  3. 比较运算符
  4. 布尔运算符
  5. 位运算符
  6. 其他运算符(void, ,

与这些运算符紧密联系的是运算符的优先级,优先级问题是笔试与面试时经常考察的问题。

算术运算符

算术运算符中最常见的是加法运算符,但是加法运算符针对不同类型的变量,组合效果有很多种。简而言之,JS中的加法运算符可以实现数字的相加,也可以实现字符串的拼接。

// ————数字相加————
console.log(1 + 1);  // 2
console.log(true + true);  // 2
console.log(1 + true);  // 2
console.log(false - 1);  // -1
// ————字符串拼接————
console.log('1'+'1');  // '11'
console.log('1.1' + ' ' + '1.1');  // '1.1 1.1'

加法的计算方法一般如下:

如果运算元素是对象,那么会先转化为原始类型的值(即valueOf方法),如果其结果还不是原始类型的值,再调用toString方法

var obj = {name: 'Lyndon', age: 22};
console.log('1' + obj);  // '1[object Object]'
var obj = {
    name: 'Lyndon',
    toString: function toString(){
        return 'Lyndon';
    },
    valueOf: function valueOf(){
        return 'morning'
    }
};
console.log(1 + obj);  // '1morning'

var obj = {
    name: 'Lyndon',
    toString: function toString(){
        return 'Lyndon';
    }
};
console.log(1 + obj);  // '1Lyndon'

如果对象是Date实例,那么先执行的是toString方法

var day = new Date();
console.log(day);  // 'Sat Dec 31 2016 19:19:11 GMT+0800 (中国标准时间)'
console.log('good' + day);  // 'goodSat Dec 31 2016 19:19:11 GMT+0800 (中国标准时间)'

两个运算元素都是原始类型值,但只要有一个运算元素是字符串,那么另一个运算元素也会转换为字符串,执行字符串拼接

var a = 10, b = 'days';
console.log(a + b);  // '10days'

只有加号和一个运算元素,如果唯一的运算元素是字符串,那么会转换为数字,所以结果有可能是NaN

console.log(+ '78');  // 78
console.log(+ 'good');  // 'NaN'

否则,两个运算元素皆转换为数值,执行算术加法运算

由于加法运算极大地依赖于参数的类型,因此使用时应该首先明确到底要执行哪种运算,如果不确定最好加上小括号。如下面的例子就说明字符串在算式中的位置不同,结果也会不同。

console.log('3' + 4 + 5);  // '345'
console.log(3 + 4 + '5');  // '75'
console.log(3 + '4' + 5);  // '345'

特别需要注意的还有两点

  1. 加法运算符对于其他类型的值会自动转化为字符串,然后进行字符串的拼接。
var a = [1, 2];
var b = 3;
console.log(a instanceof(Object));  // true
console.log(a + b);  // '1,23'
2 + [2];  // '22',等同于String(2) + String([2])
  1. 如果只有一个运算元素,必须将其放在右边
2 + ;  // Uncaught SyntaxError: Unexpected token ;
console.log(2 + );  // Uncaught SyntaxError: Unexpected token )
+-6;  // -6,等同于+(-6)
 + 3 + 4;  // 7,等同于+(3+4)

相较加法运算符而言,剩下的算术运算符都相对简单些,其原则就是:将所有的运算元素全部转换为数值,再执行相应的算术运算。

'1'/2;  // 0.5
'a'/2;  // NaN
'1a'/2;  // NaN,转换为数字的方式是Number('1a'),而不是parseInt('1a')

需要注意几个特殊的情况。

求余/求模运算,判断奇偶数时常用到%运算符,但是对于负数而言需要使用到绝对值,否则不能给出正确答案

function isOdd(n){
    return n % 2 === 1;
}
console.log(isOdd(-3));  // false
console.log(isOdd(-4));  // false

但是-3明显是一个奇数,应该返回true,所以需要进行如下修改:

function isOdd(n){
    return Math.abs(n) % 2 === 1;
}
console.log(isOdd(-3));  // true
console.log(isOdd(-4));  // false

自增与自减的运算符前后问题。如果将++--放在变量之后,会先返回变量原始值,再进行自增或自减操作;如果将符号放在变量之前,会先进行自增或自减操作,再返回操作后的结果

var a = 1, b = 1;
a1 = a++;
b1 = ++b;
console.log(a1, b1, a, b);  // 1 2 2 2

赋值运算符

常用的赋值运算符有:=, +=, -=。关于赋值运算符的主要考虑问题,应该是运算符的优先级与左结合、右结合问题。

比较运算符

比较运算符进行运算后返回的结果始终是布尔值。

==是相等,具体而言是:比较两个值是否相等;===是严格相等,具体而言是:两个值是否是同一个值,需要保证变量类型也是相同的;!=是不相等,!==是严格不相等

2 == '2';  // true
2 === '2';  // false
1 == true;  // true
1 === true;  // false
NaN === NaN;  // false,NaN与任何值都不想等,包括其自身
15 === 0xf;  // true,同类型的基础类型值,虽然进制不一样,但是代表的值相等,因此也严格相等

除了相等与严格相等运算符之外,如果两个运算元素都是字符串,那么将按照字典顺序进行ASCII值的比较;否则两个运算元素都会转换为数值进行比较

5 > '4';  // true
false < true;  // true
'cathy' > 'Cathy';  // true,因为小写字母c的ASCII值为99,而大写字母C的ASCII值为67

如果运算元素是对象,那么会先调用valueOf方法,如果返回的还是对象,接着调用toString方法

var x = [];
x.valueOf = function(){
    return 12;
}
console.log(x < '11');  // false
console.log(x > '11');  // true
var y = [2];
x > '12';  // false,等同于[2].valueOf().toString()='2'>'11'
var x = {a: 2, b: 3};
var y = {a: 3, b: 4};
console.log(x > y);  // false
console.log(x < y);  // false
console.log(x >= y);  // true,等同于x.valueOf().toString()>=y.valueOf().toString(),结果是'[object Object]'>='[object Object]'

复杂类型的比较原则:两个复杂对象是否指向同一个对象

[] === [];  // false
var a1 = [];
var a2 = a1;
a1 === a2;  // true

相等运算符:对于基础类型的值会转换成数值类型再进行比较;如果对象与基础类型值比较,会先将对象转化为原始类型的值,再进行比较

[1] == 1;  // true
[1] == '1';  // true,等同于Number(String([1]))==Number('1')
[1] == true;  // true

相等运算符之后隐藏的类型转换,往往会使人困惑,因此最好广泛使用严格相等运算符,少使用相等运算符

布尔运算符

布尔运算符用于将表达式转换为布尔值。

取反运算符会自动将非布尔值转换为布尔值,以下是能够转换为false的5个值,对于其取反就能转换为true。两次取反是将一个值转换为对应布尔类型的简便方法

!undefined;  // true
!null;  // true
!'';  // true
!0;  // true
!NaN;  // true
!!NaN;  // false

且运算符(&&):如果第一个运算元素的布尔值为true,那么会返回第二个运算元素的值;如果第一个运算元素的布尔值为false,那么直接返回第一个运算元素的值。这种跳过第二个元素的机制常被称为"短路"

var a = 2;
console.log('hello') && (a - 2);  // undefined,等同于console.log('hello')并不返回任何值,所以是undefined,而!!undefined=false,所以直接返回第一个运算元素的值:undefined

或运算符(||):如果第一个运算元素的布尔值为true,那么会返回第一个运算元素的值;如果第一个运算元素的布尔值为false,则返回第二个运算元素的值

var a = 2;
console.log('hello') || (a - 2);  // 0,等同于第一个运算元素的布尔值为false,那么返回第二个运算元素的值0

三元运算符(?:):与if...else...条件判断语句有着相同的表达效果,但是三元条件运算符有返回值,if...else...却没有

console.log(0 ? true : false);  // false
console.log(1 ? true : false);  // true

位运算符

位运算符中比较常用的是:或运算与与运算。位运算符直接处理的是每一个比特位,是非常底层的运算,常常用在加密算法中,好处是速度比较快,缺点是不直观,增加了代码的复杂度,提升了维护成本。

或运算(or):符号为|,两个二进制位都为0,则结果为0,否则为1
与运算(and):符号为&,两个二进制位都为1,结果为1,否则为0

console.log(1 | 3);  // 3,等同于:1表示为二进制是001,3表示为二进制是011,因此最后结果为011,转化为十进制即为3
console.log(1 & 3);  // 1,等同于:1表示为二进制是001,3表示为二进制是011,因此最后结果为001,转化为十进制即为1

位运算符仅仅对整数有效,遇到小数时,会将小数点后的部分抹去,只保留整数部分。

console.log(1 | 3.965);  // 3

在JS内部,数值都是以64位浮点数的形式进行存储,但是进行位运算的时候,是以32位进行运算的。也即2在JS内部是00000000000000000000000000000010,因此进行否运算时,原来的0全部变为1,而1变为0。因此-2进行否运算后第一位是1,所以这个数是一个负数。但是JS采取补码的方式来表示负数,因此需要将这个数减去1,再取一次反,所以最后的结果是00000000000000000000000000000011,加上负号后就是-3

console.log(~2);  // -3

void运算符

void运算符的作用是:执行表达式,然后只返回undefined,由于void的优先级比较高,因此使用时最好加上小括号

console.log(void 1 + 2);  // NaN,等同于:undefined + 2
console.log(void(1 + 2));  // undefined

逗号运算符

逗号运算符的作用是对两个表达式求值,然后返回后一个表达式的值。

1, 10;  // 10

var x = 1;
var y = 10;
var z = (x, y);
z;  // 10
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容