栈(stack)&&堆(heap):
栈(stack)内存:操作系统分配的固定空间,程序运行结束后自动释放,储存基本变量,以及一些对象的引用变量;JavaScript中的基本数据类型(String,Boolean,Number,Undefined,Null);
堆(heap)内存:操作系统动态分配空间,空间大小不定,不能自动释放(可通过人为操作或者垃圾回收机制释放);在堆中的变量可能在多个地方引用达到代码重复使用的目的;JavaScript的引用数据类型(Array,Function,Object);
注释:才疏学浅,多方借鉴,方能一吐笔墨,接下来有请灵魂画手---当代非著名画家闪亮登场!
传值&&传址:
先扫一眼这几行代码 0_0
testArray(){
let a = [1,2,3,4,5];
let b = a;
b[0] = 7
let c= 0;
console.log(`a-->`,a); // a--> (5) [7, 2, 3, 4, 5]
console.log(`b-->`,b); // b--> (5) [7, 2, 3, 4, 5]
console.log(`c-->`,c); // c--> 0
}
惊奇的发现:
- [1,2,3,4,5]赋值给a,a赋值给b,输出a,b惊人的一致;
- 修改b[0]值,结果数组a也发生了一内内变化;
- 修改c,a和b并没发生改变(大哥,先把刀收起来,自己人),其实我是把b[0]赋值给c,输出一下,然后把0又赋值给c的,代码上没写b[0]赋值给c的!
- 这时我想stack和heap这俩货在做什么见不得人的操作,这时我突然想起来鲁迅,对,就是那个学生时代我最恨得人,课文不是要背诵就是谈理解T_T;
鲁迅说:你们抓周树人和我鲁迅有啥关系!就好像说你操作b,跟我a有啥联系一样,别说,还真有关系;
我去找找砸门的灵魂画手 ^_^
我简单画了一下,数组a,是引用数据类型在堆(heap)里面;也就是说当a赋值给b的时候,是把heap里的地址赋值给了b,自然操作b时会联动a也发生里改变;而c是仅仅从a获取里一个数值,这个数值是Number,存放在stack里面,修改c是在stack里面修改;
浅拷贝&&深拷贝:
我们知道基本数据类型和引用数据类型分别在stack和heap里面,理解浅拷贝和深拷贝就容易了!(我是这样认为的)
浅拷贝:
copy(){
let a = {
A : "A"
};
a.AA = ["A","AA"];
let b = shallowCopy(a);
console.log(`a-->`,a); // a--> {A: "A", AA: ["A","AA"]}
console.log(`b-->`,b); // b--> {A: "A", AA: ["A","AA"]}
function shallowCopy(o) {
let c = {};
for(let i in o){
c[i] = o[i];
}
return c;
};
}
对b进行b.AA.push("AAA")操作之后:
copy(){
let a = {
A : "A"
};
a.AA = ["A","AA"];
let b = shallowCopy(a);
b.AA.push("AAA")
console.log(`a-->`,a); // a--> {A: "A", AA: ["A","AA","AAA"]}
console.log(`b-->`,b); // b--> {A: "A", AA: ["A","AA","AAA"]}
function shallowCopy(o) {
let c = {};
for(let i in o){
c[i] = o[i];
}
return c;
};
}
惊奇发现:操作b时,联动a也发生一内内变化;明显我们操作得是变量b里面的数组!
接下来再操作b,给b里面添加一个{B:"B"} 代码:
copy(){
let a = {
A : "A"
};
a.AA = ["A","AA"];
let b = shallowCopy(a);
b.AA.push("AAA")
b.B = "B";
console.log(`a-->`,a); // a--> {A: "A", AA: ["A","AA","AAA"]}
console.log(`b-->`,b); // b--> {A: "A", AA: ["A","AA","AAA"],B: "B"}
function shallowCopy(o) {
let c = {};
for(let i in o){
c[i] = o[i];
}
return c;
};
}
惊奇发现:操作b里面的数组会联动到变量a,那为什么操作b,不操作b里面对象A和数组AA时,也不见变量a里面添加B:"B",为什么啊!
请非著名画家---->
呸....画的真丑!
简单理解就是:当对变量a进行拷贝时,a变量中遇到基本数据类型直接以等号复制,如果在a变量中有引用数据类型比如上图中的AA是一个数组,Array是引用数据类型,在堆中且有地址,所以b拷贝过去的其实是AA在堆里面的地址,这也就是说,为什么对b里面的数组进行操作会联动到a里面的数组了!
深拷贝:
理解浅拷贝,那根据浅拷贝的提示,直接对拷贝对象中引用数据类型进行递归层层赋值就行了;
copy() {
let a = {
A: "A",
};
function deepCopy(o, c) {
var c = c || {} || [];
for (let i in o) {
if (typeof o[i] === "object") {
c[i] = o[i].constructor === Array ? [] : {};
deepCopy(o[i], c[i]);
} else {
c[i] = o[i];
}
}
return c;
}
a.AA = ["A", "AA"];
let b = {};
b = deepCopy(a, b);
b.AA.push("AAA");
b.B = "B";
console.log(`a-->`, a); // a--> {A: "A", AA: ["A","AA"]}
console.log(`b-->`, b); // b--> {A: "A", AA: ["A","AA","AAA"],B: "B"}
}
如上所见,对b进行push()操作还是添加B都没有联动到a,a真特么稳如老狗!
图我就不画了,递归层层赋值copy,a里面的AA和b里面的AA已经不是一个堆地址!