第18题 - 被小看的传值 or 传引用

640?wx_fmt=png

前几天一个正在找工作的朋友发来一个面试题,感觉挺有意思的今天发出来大家一起乐呵乐呵。

这个题其实不难,但是涉及到不只一个知识点,而且平时可能不会注意到。

来直接看题

640?wx_fmt=png

得到这个题后也发给了自己的小伙伴儿一起研究了下,得出的很多种答案。

从各自的答案中也找到了一个相同的问题,也就是不能确定的值是 d 的值,

有的得出【4,5,6】,有的得出【1,2,7】。

你可以现在脑子里写出答案?

640?wx_fmt=png

~~~

640?wx_fmt=png

~~

640?wx_fmt=png

~~

正确答案是:1,3,[1,2,7],[1,2,7],[1,2,7]

如果答案一致请忽略本文

我们来一步一步的分析下。

1. 首先 a 和 b 的值我们都能确定的给出 a=1,b=3;

因为 console 是在全局作用域执行的,所以即便是这个自执行函数执行后 a 也不可能是函数内部的值。他们两个的作用域不同,所以 a=1;

2. b 的声明和赋值在全局存在,在自执行函数内也被赋值一次,所以 b=3;

3. 剩下的就是 cde 的值了

题目中的 c d e 的连等更多的是一种混淆,不用管它,当做是正常的赋值即可。

先来看 c 的值

c 在全局被赋值为一个数组,所以他是引用类型(大家都知道),

在函数中又被赋值一次c[2]=7,先不管后面的代码如何,这个时候 c 的值肯定是 [1,2,7]了,此时 d 和 e 的值也是[1,2,7]

因为 cde 指向的是同一块内存区域,修改后引用的数据就变成了[1,2,7]

640?wx_fmt=png

然而c 赋值后面还有d=[4,5,6]

那形参 d 的重新赋值会影响 c 的值吗?

答案当然是不会影响。

首先看清楚形参d对应的是实参 e,重新给 d 赋值其实在操作 e(不够准确,后面会说);

然而 e 是数组是引用类型,所以有的答案存在e =[4,5,6]或者d=[4,5,6];

其实这里首先要搞清楚一点,两个变量指向同一内存区域,如果其中一个变量重新赋值(而不是修改值),是不会影响另一个变量的,因为重新赋值会切断对原来内存地址的引用,从而指向新的地址。

640?wx_fmt=png

所以肯定的是 c 的值不会受影响,所以 c=[1,2,7];

求 d 的值?

d 在函数内部被重新赋值,因为他是形参(对应的实参是 e),而且也是函数的局部变量,所以 全局d 的值不会因为重新赋值而改变,但是 c 对引用的数据做了修改,所以d 也会改变 d=[1,2,7]

求 e 的值?

e 是函数的实参,对应的形参是 d。

这里就要知道函数的参数传值的方式是怎样的-按值传递和按引用传递。

记得在高程里有提起过,js 中函数参数只有按值传递的方式,没有按引用传递。也就是传递的是变量的副本,其实就是两个变量。

所以在函数内部的 d 被重新赋值,其实修改的是 e 的副本,但是 d 被重新赋值了,所以d 和 e 就没有了关系。e 还是原来的指向。所以 e=[1,2,7]。

如果 d是这么修改值,d[2]=8 ,那么 c d e=[1,2,8]了。

按引用传递

如果参数是按引用传递,那么就不是副本了,会直接修改原变量,结果就可想而知了。

对比下其他语言

php

640?wx_fmt=png

可以强制按引用传递

640?wx_fmt=png

C#

640?wx_fmt=png

640?wx_fmt=png

java 肯定也是默认按值传递。

总结

这个面试题考点主要有:

作用域

基本类型和复杂类型的赋值和改值

函数参数传递的方式

后端语言也是默认按值传递,也就是处理的是变量的副本,如果变量是值类型,那么随便修改也不会影响原变量。

如果是引用类型(复合类型),若是修改的话那会直接影响原变量,如果是从新赋值就会重新分配内存区域对原变量无影响。

有些后端语言还可以强制按引用传递(按需处理)。

相关资料:

java的

https://www.cnblogs.com/lixiaolun/p/4311863.html

有兴趣可以看看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用辗转相除法和最小公倍数的性质来解决这个问。具体步骤如下: 1. 定义一个函数 gcd(a, b),用于求两个数 a 和 b 的最大公约数。可以使用辗转相除法来实现。 2. 定义一个函数 lcm(a, b),用于求两个数 a 和 b 的最小公倍数。根据最小公倍数的定义,它等于 a 和 b 的乘积除以它们的最大公约数,即 lcm(a, b) = a * b / gcd(a, b)。 3. 对于输入的 n,从 1 到 n 依次计算它们的最小公倍数,每次计算都将结果保存下来。具体来说,可以使用一个变量 ans 来记录当前的最小公倍数,初始为 1,然后对于每个 i(1 <= i <= n),更新 ans 为 lcm(ans, i)。 4. 最后返回 ans,即为 1~n 的最小公倍数。 下面是 Python 代码实现: ```python def gcd(a, b): """求两个数的最大公约数""" while b: a, b = b, a % b return a def lcm(a, b): """求两个数的最小公倍数""" return a * b // gcd(a, b) def smallest_lcm(n): """求1~n的最小公倍数""" ans = 1 for i in range(1, n+1): ans = lcm(ans, i) return ans # 测试 print(smallest_lcm(10)) # 输出 2520 print(smallest_lcm(20)) # 输出 232792560 print(smallest_lcm(100)) # 输出 69720375229712477164533808935312303556800 ``` 注意,当 n 很大时,最小公倍数可能会超出 Python 的整数范围,导致计算结果不正确。这时可以使用 Python 中的 Decimal 类型来避免这个问。例如,将最小公倍数的计算结果存储在一个 Decimal 对象中,每次更新时也需要使用 Decimal 类型的 lcm 函数来计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值