JS 的引用赋值与传值赋值
这个问题说大不大说小不小,如果你有幸踩了这个坑,一定会找这篇文章,哈哈~
现说一下JS数字的类型:基本类型和引用类型
先看下下面两个栗子:
var a = 30; var b = a; a = 20; console.log( b ) // 30 var a = [1,2]; var b = a; a[0] = 5; console.log( b ) // [5,2]
简单的说:
number,string类型都是基本类型,而基本类型存放在栈区,访问时按值访问,赋值是按照普通方式赋值;
对象和数组是通过引用来赋值的,所以改变a的同时b也会跟着改变。
解决办法:
好了下面详细的说,看了上面秒懂的直接忽略(直接看下面阿里的面试题);
1、基本类型
基本的数据类型有:undefined,boolean,number,string,null。 基本类型存放在栈区,访问是按值访问的,就是说你可以操作保存在变量中的实际的值。
当基本类型的数据赋值时,赋得是实际的值,a和b是没有关联关系的,b由a复制得到,相互独立。(字面量的才是基本类型)
var a=10;
var b=a;
console.log(a+','+b); // 10,10
a++;
console.log(a+','+b) // 11,10
2、引用类型
引用类型指的是对象。可以拥有属性和方法,并且我们可以修改其属性和方法。引用对象存放的方式是:在栈中存放对象变量标示名称和该对象在堆中的存放地址,在堆中存放数据。
对象使用的是引用赋值。当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在堆中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
3、数组是引用类型
我们先来看一个例子:
var a = [1,2,3];
var b = a;
a = [4,5,6];
alert(b); //[1,2,3]
好像数组是基本类型一样。。,但是:
var a = [1,2,3];
var b = a;
a.pop();
alert(b); //[1,2]
这是怎么回事?因为:(知乎解释)
作者:Intopass
链接:https://www.zhihu.com/question/26042362/answer/31903017
来源:知乎
var tasks=this.state.data;
tasks=tasks.filter(function(i){
return i.index!=taskId;
});
由于filter函数是返回一个新的数组,虽然仍然用tasks去接收,但这时候tasks的指向已经是新数组啦,所以tasks和data已经不在有关系。(concat也是返回新数组)
而push和splice函数是在原数组上操作,所谓在原数组操作,指的是指向不变,所以tasks和data是相关联的。
4、参数传递
js的函数参数传递为值传递。
当传入的是 基本类型的参数时:就是复制了份内容给i而已,i与age之间没有关系。
function setAge(i)
当传入的参数为引用类型时:
function setName(obj)
这是阿里2014年的笔试题:
var a = 1;
答案:12
首先test传递进去的实参中,a是基本类型(,复制了一份值),obj是object(指向地址,你动我也动),fn也当然不是基本类型啦。在执行test的时候,x被赋值为4(跟a没关系,各玩各的,a仍然为1),y的b被赋值为5,那obj的b也变为5,z的c变为6,那fn的c当然也会是6. 所以alert的结果应该是1+5+6 =12. (其实test不返回z也一样,z仍然改变的)。
var a = 30;var b = a;a = 20;console.log( b )
var a = [1,2];var b = a;a[0] = 5;console.log( b )