这个题其实不难,但是涉及到不只一个知识点,而且平时可能不会注意到。
来直接看题
得到这个题后也发给了自己的小伙伴儿一起研究了下,得出的很多种答案。
从各自的答案中也找到了一个相同的问题,也就是不能确定的值是 d 的值,
有的得出【4,5,6】,有的得出【1,2,7】。
你可以现在脑子里写出答案?
~~~
~~
~~
正确答案是: 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]
然而c 赋值后面还有d=[4,5,6]
那形参 d 的重新赋值会影响 c 的值吗?
答案当然是不会影响。
首先看清楚形参d对应的是实参 e,重新给 d 赋值其实在操作 e(不够准确,后面会说);
然而 e 是数组是引用类型,所以有的答案存在e =[4,5,6]或者d=[4,5,6];
其实这里首先要搞清楚一点,两个变量指向同一内存区域,如果其中一个变量重新赋值(而不是修改值),是不会影响另一个变量的,因为重新赋值会切断对原来内存地址的引用,从而指向新的地址。
所以肯定的是 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
可以强制按引用传递
C#
java 肯定也是默认按值传递。
总结
这个面试题考点主要有:
作用域
基本类型和复杂类型的赋值和改值
函数参数传递的方式
后端语言也是默认按值传递,也就是处理的是变量的副本,如果变量是值类型,那么随便修改也不会影响原变量。
如果是引用类型(复合类型),若是修改的话那会直接影响原变量,如果是从新赋值就会重新分配内存区域对原变量无影响。
有些后端语言还可以强制按引用传递(按需处理)。