值传递和引用传递
值类型变量:
存在内存的堆中,比如:a=1
引用类型变量 :
1.指针存在于栈中,2.引用类型的具体内容存在于堆中 ex:let a={b:1} a的指针指向 堆中的地址0xffac0ec
正如我在 第二章 说的,
- number
- string
- boolean
这三种常规类型的是值传递, 而array,对象这种就属于引用传递了。
代码来说话,我们先看看
值传递:
var int1 = 12;
var int2 = int1;
int1 = 10000;
console.log(int2);var b1 = true;
var b2 = b1;
b2 = false;
console.log(b1);var str1="hello world";
var str2=str1;
str2="高司机,出bug了";
console.log(str1);
输出结果为
12
true
hello world
引用传递:
let obj1 = {};
let obj2 = null;
obj2 = obj1;
obj1.a = "a";
obj2.b = "b";
//引用类型 指向 同一个堆的区域
console.log(obj1);
console.log(obj2);
输出结果为
{ a: 'a', b: 'b' }
{ a: 'a', b: 'b' }
在逻辑运算中使用值传递和引用传递
let v1 = new String("hello world");
let v2 = v1;
v1 = "出BUG了"; console.log(v1);
console.log(v2);
不知道是不是和你想的一样,结果是下main的
出BUG了
[String: 'hello world']
我们来分析下://第二行v2引用的是V1,当运行到第三行的时候v1 变为基本类型时,相当于在内存中有一个新的堆空间,v1的内存地址指向自己本身堆的地址,所以v1输出“出BUG了”,那么v2呢,v2依然是对象类型 而v2不受v1的改变而改变,依然是通过栈的指针 指向new String('"helloworld')对象的内存地址。
在函数中使用值传递和引用传递
function addOne(num) {
num += 1;
return num;
}var count = 10;
var result = addOne(count);
console.log(count);
console.log(result);
/调用addOne(num) 参数num相当于 在方法中拷贝了一个新的num值在堆中,方法内的改变,不会影响到外部变量
10
11
引用传递
let objj = { a: 1 };
function objAdd(obj) {
obj.b = 1;
}
objAdd(objj);
//引用传递,相当于传递的是obj的指针,会影响外部变量 堆中的值
console.log(objj);
{ a: 1, b: 1 }
在引用和值传递中交叉使用
var person = new Object();
var obj = person; // 赋值
obj.name = "ABC";
obj = new Object(); // 指向 新的对象
obj.name = "BCD";
console.log(person.name); // 指向老的对象 不受影响
console.log(obj.name); // 指向新的对象
console
ABC
BCD
深拷贝和浅拷贝
之前在第二章节我答应过要专门说深拷贝和浅拷贝,这个原理实际上和C++是类似的。
实际上浅拷贝你可以理解为简单的引用拷贝。
所谓深拷贝就是自己新建一个数组或者对象,把源数组或者对象中的基础类型变量值一个个手动拷过去,而不是只把源数组或者对象的引用拿过来。所以这就涉及到了一个递归的调用什么的。
下面是我实现的一个深拷贝函数,大家可以写一个自己的然后加入到自己的 nodejs 知识库中。
function cloneObject(src) {var dest = {};for(var key in src) {if(typeof src === "object") dest[key] = cloneObject(src[key]);else dest[key] = src[key];}return dest;
}