刘志龙

2015-11-29 22:47

神奇运算符

本文作者:IMWeb 刘志龙 原文出处:IMWeb社区 未经同意,禁止转载

每一门编程语言的设计都离不开运算符,我们写的每一行代码基本也少不了它们,这篇文章就让我们一起来了解一下这个无处不在的小伙伴的应用和小技巧吧~~

~ 按位取反

字符串查找

写JS的时候我们查找字符串时经常这么写判断字符串是否存在特定字符:

if (str.indexOf('a') != -1) {
    ...
}

这边其实可以利用~的一个小技巧,因为~-1 = 0,上面的这个判断我们可以简单用~ 进行替换:

if (~str.indexOf('a'))
    ...
}

看起来比 != 有趣多了~~

取整

正数像下取整我们用的最多的应该是类似这样:

var a = 2.3;
var b = Math.floor(a);

其实用~也可以很完美的替换整数向下取整:

var a = 2.3;
var b = ~~a;

&& 与 ||

这两兄弟基本上经常都会在一起被看到,所以这边也一起介绍一下它们。

var result; 

if status == 1) {
    result = 'Andy'
} 
else if(status == 2){ 
    result = 'Tom';
}
else { 
    result = 'John';
}

上面这种if else的代码我们用到的不能再多了。代码当然完全没有问题,看起来也很直观,如果条件多了我们也可以用switch替换,这应该是我们用的最多的方式,可读性也很好。但是我们这里思考一下是否用&& 与 || 也能达到一样的效果呢?

var result = (status == 1 && 'Andy') || 
    (status == 2 && 'Tom') || 'John';

上面这样一简单的语句作用就和前面的if else效果一样,让我不得不惊叹这对兄弟的强大。当然这也是以牺牲可读性为代价的,所以在写类似这样的代码时,简单的注释还是需要的。

感受了上面这种简洁的办法之后,本来以为应该没有办法用更少的字符达到一样的效果了吧。

但是答案是否定的,下面这条语句用各少的字符做到了一样的效果:

var result = {'1': 'Andy', '2': 'Tom'}[status] || 'John';

当JS用上位运算,原来也可以这么酷!

当然了,比起上面这些用的相对少之外,大家用的最多的无非是利用“短路”原理做一些更简单的判断。

所以这边还是顺带提及一下平常用的比较多的。

判断变量是否定义过了:

var test = test || '1';

平常的简单条件判断:

if (a === 'Andy'){ 
    console.log ('hello ' + a);
}

一般也简单用&&替换:

    a === 'Andy' && console.log ('hello ' + a);

好吧,我们最常用到的&& 与 || 两兄弟就先简单介绍到这里了。

^ 运算符

写一些逻辑性的代码时经常要用到两数交换,一般都这样写:

var a = 1, b = 2, temp;

temp = a;
a = b;
b = temp;

大一那时候不知道^也可以做两数交换,当第一次看到原来不需要额外参数也可以交换两个数字的时候也着时感叹了一下异或的神奇~

var a = 1, b = 2;

a = a ^ b;
b = b ^ a;
a = a ^ b;

简单的证明一下上面的代码:

为直观一点方便证明让 aa = a, bb = b

// a = a ^ b
a = aa ^ b  

// b = b ^ a
b = aa
  = aa ^ 0
  = aa ^ (bb ^ bb)
  = bb ^ (aa ^ bb)
  = bb ^ a   

// a = a ^ b
a = bb
  = bb ^ 0
  = bb ^ (a ^ a)
  = a ^ (bb ^a)
  = a ^ b

说到这里不得不提到一个经常被问到的面试题:在一个n - 1 的数组中不重复分布着1 ~ n 这n个数字,找出不在数组中的那个数字是啥?

估计回答最多的是用一个标记数组,然后循环一遍标记一遍。这个题目O(n)的时间效率无可厚非,那空间上怎么优化呢?

后来有人提出一种办法优化空间,把1 - n都加起来减去 n - 1 的数组的和 就得到要找的数了,非常好的办法,也不再需要O(n)的标记数组了。

除了这种办法,还有别的吗? 异或一样可以告诉我们答案,利用亦或的结合律,把n -1 数组中的所有数字异或再与 1~n 异或就得到答案了,简单证明下:

为了简单证明我们假设arr[1] = 1, arr[2] = 2, 以此类推。
a = (arr[1] ^ arr[2] ... ^ arr[n-1]) ^ (1 ^ 2 ... ^ n - 1 ^ n)
  = (arr[1] ^ 1) ^ (arr[2] ^ 2) ... ^ (arr[n-1] ^ n-1) ^ n
  = 0 ^ 0 .. ^ 0 ^ n
  = n

像好多找什么数组中重复的数字啊什么的,一样的道理可以用异或。

扯的有点远了。。。回到主题继续。

其他好玩的运算符

刚刚说到正整数 ~~ 可以向下取整,其实除了这个,还有好多办法:

var a = 2.3, b = 2.3, c = 2.3;

a = a >> 0;
b = b << 0;
c = c | 0;

说到这个,突然像到上面的代码可以做字符串转数字的方法,我们一般的写法都是:

var a = '100';
a = a - '0';

或者这样:

var a = '100';
parseInt(a, 10)

其实可以更简单的写成这样

+"100"

// 正整数
"100" | 0
"100" >> 0
"100" << 0

位运算符还有一些运算上经常用到的小技巧:

num >> 1  // 取半,偶数
num << 1  // 2倍
num & 1   // 奇偶判断

好吧,就先简单介绍到这里了,运算符还有非常多好玩的值得挖掘,熟悉运算符,能让我们写出更短更漂亮的代码~

1条评论

    您需要 注册 一个IMWeb账号或者 才能进行评论。