简介
问题是有一个变量a
、b
要怎么交换它们的值,有多少种方法,那种方法比较好比较省时省力。我们尽量使用最少的代码和内存空间来实现变量的交换。
下面我们分别使用五种类型的方法实现变量交换,它们都有自己的优缺点,五种方法如下:
借助临时变量
ES实现方法
通过加减法
按位异或
利用逗号操作符
借助临时变量
首先来一个最简单的实现方式代码如下:
1 | var a = 100; |
这个我们多使用了一个变量temporary
,这种方法也是我们经常用的。如果我们不声明一个临时变量怎么实现呢。
本方法优点是实现简单,缺点是多声明一个变量,在执行期间多占用内存,并且要记得在最后执行完成记得清空变量
ES 实现方法
我们可以使用ES6
中的解构
特性,这个应该也是比较常用的方法。但是兼容性没有上面的方法好,但是在Vue
、React
中经常用到。
1 | var a = 100; |
本方法优点代码简洁并且没有声明多余变量,缺点是兼容性并不太理想
如果不使用ES6
中的特性,实现代码如下:
1 | var a = 100; |
我们通过把a
设置为一个对象用来保存a
、b
的值,然后再分别取出。通过把对象替换为数组也是可以实现,这里就不做演示了。
本方法优点并且没有声明多余变量,缺点是改变变量的类型在执行期间多使用内存
通过加减法
通过加减法也是可以实现的,首先是通过加法
实现,代码实现如下:
1 | var a = 100; // 初始值 a |
但是这种方式可能会导致数字溢出,所以我们可以通过减法
来实现更安全。下面看代码实现:
1 | var a = 100; // 初始值 a |
加法的实现更好理解,但是存在整数溢出的风险;减法的实现不太好理解,但是并不会存在整数溢出的风险
按位异或
首先我们要了解一下什么是按位异或,它的定义是按位异或(XOR):a ^ b对于每一个比特位(二进制 base 2),当两个操作数相应的比特位(二进制 base 2)有且只有一个1时,结果为1,否则为0。
a | b | a XOR b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
可能看到上面还是有点懵逼,那么可以看我另外一篇的博客了解 JS 中的位运算符
我们通过上面的表格知道a ^ a
为0
,那么a ^ a ^ b
就相当于0 ^ b
的出来的值为b
的值。代码如下实现如下:
1 | var a = 100; // 初始值 a |
按位异或:实现方式最好,直接通过二进制对比实现、代码简洁,但是转换过程不可知
利用逗号操作符
也可以通过一些特殊的技巧来实现,逗号操作符
结合()
或者[]
来实现交换位置。
我们简单了解一下逗号操作符:对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
,来一个简单的实例:
1 | var x = 1; // 初始值 x = 1 |
我们以对象为示例大致分析一下它的执行顺序,以便于更好的理解JavaScript
的执行顺序:
- 声明变量
y
,并且给y
赋值为1
()
的优先级是最高的,然后是++
>+
优先级次之,再是=
>,
。执行优先级如下表格所示。- 所以会先执行外部的
()
, 执行内部的代码,遇到,
符从左开始执行(0, (y++))
,遇到内部的(y++)
这个时候因为()
的优先比++
的优先级高,所以执行结果就是(0, 1)
。再执行,
符他返回了一个1
. - 再执行外部的
y = y + 1
,它们的优先级为+ > =
,先执行y + 1
再执行y = 2
,所以最后y
为2
。
优先级 | 运算类型 | 关联性 | 运算符 |
---|---|---|---|
20 | 圆括号 | n/a(不相关) | ( … ) |
17 | 后置递增(运算符在后) | n/a | … ++ |
16 | 一元加法 | 从右到左 | + … |
3 | 一元加法 | 从右到左 | … = … |
0 | 赋值 | 从左到右 | … , … |
下面我们就通过逗号操作符
来实现两值交换,通过数组实现
代码如下:
1 | var a = 100; // 初始值 a |
方法()
实现代码如下:
1 | var a = 100; // 初始值 a |
优点实现简洁,更灵活,数组的操作还是容易理解一点,但是”,”操作符不太好了解
总结
通过上面 5 种方法我们开扩了自己的思路,即复习了ES6
也了解执行优先级
、按位操作符
、,
等等。所以是比较有趣的,如果你有更好的解法请留言,大家一起进步。个人认为最好的方法是按位操作符
、减法实现
是比较好的实现方法。