被小看的面试题 - 传值 or 传引用

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

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

来直接看题


de1f11b722d97be391bef9e485d59b04_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


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

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

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


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


4fa6d76895d298f0adf2b7dd16236894_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


~~~


4fa6d76895d298f0adf2b7dd16236894_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


~~


4fa6d76895d298f0adf2b7dd16236894_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

~~


正确答案是: 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]


8f75b6b215375ece382d09a04b004767_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

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


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

答案当然是不会影响。


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

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


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


c97377c51328be0a339d9275ee6830ab_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


所以肯定的是 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

d282e8e9c55bab189cb8bf737fe19c3a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


可以强制按引用传递

73e976759d83a629e5cb2c59b34d3fe1_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


C#

8ca45474f81c9f46e19366f467212f53_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


d9094cb024cb16a0a62ea9b3f740704a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


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


总结


这个面试题考点主要有:

作用域

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

函数参数传递的方式


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


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


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

目录
相关文章
|
7月前
【面试题精讲】形参&实参
【面试题精讲】形参&实参
|
8月前
|
C++ Python
Python函数参数传递:传值还是传引用
Python函数参数传递:传值还是传引用
41 0
|
8天前
传址与传值
传址与传值
18 0
【面试知识点】形参和实参的区别
【面试知识点】形参和实参的区别
|
Java
08 java中方法传参的传值与传址问题
java的值传递与址传递 问题:在java中方法传参到底是值传递还是址传递?
82 0
08 java中方法传参的传值与传址问题
细说值传递、引用传递和地址传递
细说值传递、引用传递和地址传递
|
PHP 开发者
变量传值| 学习笔记
快速学习变量传值。
64 0
C | 传值调用&传址调用(进阶版)
调用函数有两种方式,传值调用和传址调用,其中包含很基础很基础的细节,一定要掌握!
99 0
C | 传值调用&传址调用(进阶版)
|
Java
Java面向对象-方法的值传递和引用传递
Java面向对象-方法的值传递和引用传递
95 0
|
C语言
【C语言深度剖析】重点详解函数的形参和实参、传值和传址
【C语言深度剖析】重点详解函数的形参和实参、传值和传址
150 0
【C语言深度剖析】重点详解函数的形参和实参、传值和传址