数据类型
基本数据类型
number、string、boolean、null、undefined 基本数据类型的值保存在栈中;
引用数据类型
array、object、function 等对象,引用类型的数据保存分为两部分:
- 地址
- 值
其中栈中是保存地址的引用,堆中保存真正的值 如
什么是按值传递?什么是按引用传递?
按值传递(call by value):函数的形参是被调用时所传实参的副本,修改形参的值并不会影响实参。
按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改,同时两者指向相同的内存地址。
Js传递方式
参数是基本数据类型:
1 var a = 10; 2 function add(a) { 3 a = 20; 4 console.log(a);//20 5 } 6 add(a); 7 console.log(a);//10
变量a在add 内部改变了值,并没有影响到外部的a变量;
参数是引用类型:
1 //引用类型 2 var person = {name: ‘joel‘, age: 11} 3 function foo(o) { 4 o.name = ‘alen‘;//改变对象的值 5 o = {name: ‘elire‘}//改变对象的地址 6 console.log(o.name); //elire 7 } 8 foo(person); 9 console.log(person.name);//alen
如果是按照引用传递,传进去的o对象跟外部的person对象指向的内存应该是同一个,但是foo()内部o.name 是elire,外部的person.name 是alen,所以尽管是引用类型数据传递的时候也不是按引用传递;
继续看下面demo:
1 var v1 = [] 2 var v2 = {}; 3 var v3 = {}; 4 function demo1(v1, v2, v3) 5 { 6 v1 = [1]; 7 v2 = [2]; 8 v3 = {a:3} 9 } 10 demo1(v1, v2, v3); 11 console.log(v1); // 空白 12 console.log(v2); // [object Object] 13 console.log(v3.a); // undefined
由此可见:v1、v2、v3 都没有被改变,v1 仍然是零个元素的数组,v2、v3 仍然是空白的对象。即引用类型数据也是按照值传递的,先是拷贝了栈中的地址,然后在demo1()内部改变了地址的指向。
但是引用类型按值传递与基本类型数据按值传递还是有区别的。
基本数据类型,如数字、字符串是把值直接复制进去了,而引用类型 如数组、对象是把变量地址复制进去。
前面我们让 v1、v2、v3 作为参数进入函数后,就有了地址副本,这些地址副本的指向和外面的 v1、v2、v3 的地址指向是相同的。但我们为 v1、v2、v3 赋了值,也就是说我们把地址副本的指向改变了,指向了新的数组和对象。这样内部的 v1、v2、v3 和外部的 v1、v2、v3 就完全断了。
如果我们不赋新值,而是直接操作它,那么传进去的仍然是和外面的 v1、v2、v3 指向的同一块数组或对象,因为我们没有改变他们的指向。
如:
1 var v1 = [] 2 var v2 = {}; 3 var v3 = {a:0}; 4 function demo2(v1, v2, v3) 5 { 6 v1.push (1); 7 v2.a = 2; 8 v3.a = 3; 9 } 10 11 demo2(v1, v2, v3); 12 console.log(v1); // 1 13 console.log(v2.a); // 2 14 console.log(v3.a); // 3
总结
基本数据类型,如数字、字符串是把值复制进去,而引用类型 如数组、对象是把变量地址复制进去,
如果没有改变传进去的地址指向,那么它们都是指向同一个内存地址;
如果改变了地址指向那么它们跟外部的对象是两个独立的对象,互不干扰;