Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 交换值的奇思妙想 #267

Open
husky-dot opened this issue Sep 18, 2020 · 0 comments
Open

JavaScript 交换值的奇思妙想 #267

husky-dot opened this issue Sep 18, 2020 · 0 comments

Comments

@husky-dot
Copy link
Owner

作者:piyush-kochhar
译者:前端小智
来源:hackernoon

点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

早期之前,在 JS 中交换值,我们主要还是使用临时变量。ES6 之后,我们可以使用展开运算符号来交换变量,除了这两种方式,你还能想到哪些呢? 😱

本文主要介绍 交换变量的 10 种方法,请过目 😯

1. 使用临时变量

function swapWithTemp(num1, num2) {
  console.log(num1, num2)

  let temp = num1
  num1 = num2
  num2 = temp

  console.log(num1, num2)
}

swapWithTemp(66.66, 8.88)

2. 使用算术运算符+-

function swapWithPlusMinus(num1, num2){
  console.log(num1, num2)

  num1 = num1 + num2
  num2 = num1 - num2
  num1 = num1 - num2

  console.log(num1, num2)
}

swapWithPlusMinus(66, 8)

主要的过程是这样的,先求出两个数的和,那么第二个数要换友第一个数的的值就是总的和减去第二个,也就是代码中的 num2 = num1-num2,同理,第一个数要换成第二个数的值,就是总的和减去第一个数的值,现在第一个数已经是赋值给第二个数,所以直接减去第二数的值即可,也就是 num1 = num1-num2 💪

但我试了一下小数,好像有点问题,有点尴尬 😓,但这种思想我们还是要掌握的 😙

上面还可以这样来简写 👏:

function swapWithPlusMinusShort(num1, num2){
  console.log(num1, num2)

  num2 = num1 + (num1 = num2) - num2

  console.log(num1, num2)
}

这里的技巧在于 (num1 = num2) ,这步,我们让 num1 等于 num2 了,并且返回是 num2 的值,此时 num1 值已交换。 接着就用 num1 加上 (num1 = num2) 返回的值,也就是 num1 + num2 求和,然后思路就和上面分析的一样了 🙌。

但是,使用浮点数时,也会得到一些意外的结果 😵

你可以在控制台跑跑下面这段代码:


function swapWithPlusMinusShort(num1, num2){
  console.log(num1, num2)

  num2 = num1 + (num1 = num2) - num2

  console.log(num1, num2)
}

swapWithPlusMinusShort(2,3.1)

3.仅使用+-运算符

只要使用+运算符,就可以得到与同时使用+-一样的结果 👀。

function swapWithPlus(num1, num2){
  console.log(num1, num2)

  num2 = num1 + (num1=num2, 0)

  console.log(num1, num2)
}

swapWithPlus(2.3,3.4)

上面的程序可以工作,但牺牲了可读性。在()中,我们将num1分配给num2,旁边的0是返回值。简而言之,第4行看起来是这样的 ✍:

num2 = num1 + 0 => num2 = num1

4. 使用算术运算符*/

*/的原理与先前的方法相同,只是有一些微小的区别 😎。

function swapWithMulDiv(num1, num2){
  console.log(num1, num2)

  num1 = num1*num2
  num2 = num1/num2
  num1 = num1/num2

  console.log(num1, num2)
}

swapWithMulDiv(2.3,3.4)

与上一个相同。 我们得到两个数字的乘积并将它们存储在其中一个变量中,对应就是 num1 = num1*num2。然后,用总数除了对应的变量,得到交换后变量的值 😄。

但这个有些问题是什么呢?就是,如果有交换值有 0 就会得到意想不到的问题 😕:

swapWithMulDiv(2.34,0)
// 2.34 0
// NaN NaN

我们的值没有交换,而是得到一个奇怪的NaN。那是怎么回事?如果你还记得你的数学课,我们总是被告知不要除以0因为它是未定义。原因在于极限是如何起作用的,还有一些其他的原因,我们不会涉及。现在,让我们看看这个方法的其他问题:

function swapWithMulDiv(num1, num2){
  console.log(num1, num2)

  num1 = num1*num2
  num2 = num1/num2
  num1 = num1/num2

  console.log(num1, num2)
}

swapWithMulDiv(2.34,Infinity)
// 2.34 Infinity
// NaN NaN

又是NaN,因为我们不能用Infinity除以任务内容,因此未定义 ⚡。

如果是负无穷大呢,结果又会是怎么样 🌞:

function swapWithMulDiv(num1, num2){
  console.log(num1, num2)

  num1 = num1*num2
  num2 = num1/num2
  num1 = num1/num2

  console.log(num1, num2)
}

swapWithMulDiv(2.34,-Infinity)

-Infinity的结果与前面的示例相同,原因也是一样的。

下面是上面的一个简写方式,当然存在问题也是一样的:

function swapWithMulDivShort(num1, num2){
  console.log(num1, num2)

  num1 = num1*num2
  num2 = num1*(num1=num2)/num2
  num1 = num1/num2

  console.log(num1, num2)
}

swapWithMulDivShort(2.3,3.4)

5. 仅使用*/运算符

上面的程序可以工作,但牺牲了可读性。在()中,我们将num1分配给num2,旁边的1``是返回值。num2 = num1 * (num1=num2, 1)看起来是这样的:

num2 = num1 * 1 => num2 = num1

6. 使用按位异或

异或是按二进制位来工作,当我们有两个值不一样时,它的结果为1,否则为0:

function swapWithXOR(num1, num2){
  console.log(num1, num2)

  num1 = num1^num2;
  num2 = num1^num2; 
  num1 = num1^num2;

  console.log(num1, num2)
}

swapWithXOR(10,1)

4位二进制数10-> 1010

4位二进制数1-> 0001

上面的分解过程 👍:

num1 = num1 ^ num2 = 1010 ^ 0001 = 1011
num2 = num1 ^ num2 = 1011 ^ 0001 => 1010 => 10
num1 = num1 ^ num2 = 1011 ^ 1010 => 0001 => 1

我们来看另一个例子。

function swapWithXOR(num1, num2){
  console.log(num1, num2)

  num1 = num1^num2;
  num2 = num1^num2; 
  num1 = num1^num2;

  console.log(num1, num2)
}

swapWithXOR(2.34,3.45)
// 2.34 3.45
// 3 2

嗯?交换的值在哪里?我们只得到这个数的整数部分。这就是问题所在。异或假设输入是整数,因此执行相应的计算。但是浮点数不是整数,并且由IEEE 754标准来表示,该标准将数字分为三部分:一个符号位、一组表示指数的位以及另一组表示1(包括)到2(不包括)之间的数字尾数,因此我们得到了不正确的值。

另一个例子:

function swapWithXOR(num1, num2){
  console.log(num1, num2)

  num1 = num1^num2;
  num2 = num1^num2; 
  num1 = num1^num2;

  console.log(num1, num2)
}

swapWithXOR(-Infinity,Infinity)
// -Infinity Infinity
// 0 0

再一次,我们没有看到预期的结果 😱。 这是因为Infinity–Infinity都是浮点数。 正如我们上面讨论的,对于XOR,浮点数是一个问题。

  1. 使用同或门 XNOR

同或门也称为异或非门,它也可以操作二进制位,与XOR相反。当我们有两个值不一样时,XNOR 结果是0,否则为1。JavaScript 没有一个操作符来执行XNOR,所以我们使用XOR操作符来达到类似的效果。

function swapWithXNOR(num1, num2){
  console.log(num1, num2)

  num1 = ~(num1^num2)
  num2 = ~(num1^num2)
  num1 = ~(num1^num2)

  console.log(num1, num2)
}

swapWithXNOR(10,1)

4位二进制数10-> 1010

4位二进制数1-> 0001

上面的分解过程 👍:

num1 = ~(num1 ^ num2) => ~(1010 ^ 1011)=> ~(1011) => ~11 => -12

由于我们有一个负数,我们需要将其转换回二进制并执行2的补码以获取十进制值,例如:

-12 => 1100 => 0011 + 1 => 0100
num2 = ~(num1 ^ num2) => ~(0100 ^ 0001) => ~(0101) => ~5 => -6

-6 => 0110 => 1001 + 1 => 1010 => 10
num1 = ~(num1 ^ num2) => ~(0100^ 1010) => ~(1110) => ~14 => -15

-15 => 1111 => 0000 + 1 => 0001 => 1

花费了一些时间,但我们交换了价值。 但不幸的是,它遇到了与XOR相同的问题,它不能处理浮点数和无穷大 😁。

function swapWithXNOR(num1, num2){
  console.log(num1, num2)

  num1 = ~(num1^num2)
  num2 = ~(num1^num2)
  num1 = ~(num1^num2)

  console.log(num1, num2)
}

swapWithXNOR(2.3,4.5)
// 2.3 4.5
// 4 2

8. 在数组中赋值

这是一个简单的技巧,只需要一行来执行交换,更重要的是不需要数学知识,只需要一个基本的数组知识即可。

function swapWithArray(num1, num2){
  console.log(num1, num2)

  num2 = [num1, num1 = num2][0]

  console.log(num1, num2)
}

swapWithArray(2.3,Infinity)

// 2.3 Infinity
// Infinity 2.3

在数组的索引0中,我们存储num1,在索引1中,我们既将num2分配给num1,又存储了num2。 另外,访问[0],将数组中的num1值存储在num2中。

这种方式可以交换我们想要的任何东西,包括整数,浮点数(包括无穷大)以及字符串,它很整洁,但清晰度不够。

9. 使用解构表达式

这是ES6的一个特性,也是最简单的,我们可以像这样交换值 😱:

let num1 = 23.45
let num2 = 45.67

console.log(num1,num2)

[num1,num2] = [num2,num1]

console.log(num1,num2)

10. 使用立即调用的函数表达式(IIFE)

IIFE指的是在定义后立即执行的函数。

function swapWithIIFE(num1,num2){
  console.log(num1,num2)

  num1 = (function (num2){ return num2; })(num2, num2=num1)

  console.log(num1,num2)
}

swapWithIIFE(2.3,3.4)

在上面的示例中,我们立即调用第4行上的一个函数。最后的括号是函数的参数。第二个参数将num1分配给num2,第一个参数num1被返回。因此,交换了这些值,请记住,这种交换方法效率不高。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://hackernoon.com/how-to-values-in-javascript-tcr3ulr

交流

文章每周持续更新,可以微信搜索 【大迁世界 】 第一时间阅读,回复 【福利】 有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant