基础知识
1.数据结构
栈:只允许在一段进行插入和删除的线性表,是一种 先进后出 的数据结构
堆:基于 散列算法 的数据结构
队列:先进先出 的数据结构
注:
堆比栈大,栈的速度相对快
堆内存是无序存储的,根据引用直接获取
2.数据类型
基础数据类型(存储在栈内存中)
String
Number
Boolean
Undefined
Null
Symbol
引用数据类型(存储在堆内存中,再在栈内存中保存一个堆内存中的实际对象引用,引用数据的操作只是对对象引用的操作而不是实际的对象)
Array
Object
注:
基本数据类型:复制时,系统会自动为新的变量在栈内存中分配一个 新的值
引用数据类型:复制时,会在栈内存中分配一个值,这个值 仅仅是一个地址
(复制对象和原有对象具有相同的地址值,
指向堆内存的 同一个对象)
基本数据稳定,相对占用内存小;引用数据类型大小时动态的,无限的
image.png
拷贝
1.深拷贝
目标的完全拷贝,进行深拷贝后,他们 老死不相往来,谁也不影响谁
需层层递归复制对象的所有属性,包括对象的属性的属性的属性...
方式一:手写深拷贝(递归)
// 仅简单的复制对象属性不考虑它的constructor也不考虑函数正则Data等特殊数据类型
function deepCopy(obj){
if(typeof obj !== "object"){ return ; }
var str = JSON.stringify(obj);
return JSON.parse(str)
}
//
function deepCopy(obj){
var newObj = obj.constructor === Array ? []:{};
newObj.constructor = obj.constructor;
if(typeof obj !== "object"){
return ;
} else if(window.JSON){
//若需要考虑特殊的数据类型,如正则,函数等,需把这个else if去掉即可
newObj = JSON.parse(JSON.stringify(obj));
} else {
for(var prop in obj){
if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
newObj[prop] = obj[prop];
} else if(typeof obj[prop] === 'object'){
//递归
newObj[prop] = deepCopy(obj[prop]);
} else {
newObj[prop] = obj[prop];
}
}
}
return newObj;
}
方式二:jquery.extend([deep],target,object1[,objectN])
deep:Boolean。true:深拷贝,false:默认,浅拷贝
var object1 = {
apple:0,
banana:{
weight:52,
price:100
},
cherry:97
}
var object2 = {
banana:{
price:200
},
durian:100
}
$.extend(object1,object2) // object1 = {"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
$.extend(true,object1,object2) // object1 = {"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
方式三:JSON对象中的parse和stringify【仅适用于简单的情况,对象包含方法的时候,此方法不可用】
const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
2.浅拷贝
只复制引用,而未复制真正的值。
只是复制一层引用或对象的每一个属性,不会对这些属性进行递归复制
方式一:普通
var arr = ["One","Two","Three"];
var arrto = arr;
arrto[1] = "test";
document.writeln("数组的原始值:" + arr + "<br />"); //Export:数组的原始值:One,test,Three
document.writeln("数组的新值:" + arrto + "<br />"); //Export:数组的新值:One,test,Three
方式二:concat,slice只是对数组的第一层进行深拷贝
var arr = ["One","Two","Three"];
// concat
var arrtooo2 = arr.concat();
arrtooo2[1] = "set Map To";
document.writeln("数组的原始值:" + arr + "<br />"); // Export:数组的原始值:One,Two,Three
document.writeln("数组的新值:" + arrtooo2 + "<br />"); // Export:数组的新值:One,set Map To,Three
// slice
var arrtoo1 = arr.slice(0);
arrtoo1[1] = "set Map";
document.writeln("数组的原始值:" + arr + "<br />"); // Export:数组的原始值:One,Two,Three
document.writeln("数组的新值:" + arrtoo1 + "<br />"); // Export:数组的新值:One,set Map,Three
方式三:Object.assign()拷贝的是属性值,假如源对象的属性值是一个指向对象的引用,他也只是拷贝那个引用值
var newObj = Object.assign({},originObj)
方式四:手写浅复制
function shadowCopy(obj){
if(typeof obj!=='object') return;
var newObj;
if(obj.constructor === Array){
newObj = []
}else{
newObj = {};
newObj.constructor = obj.constructor;
}
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
var arr1 = [0,1,2];
console.log(arr1); // [0,1,2]
console.log(shadowCopy(arr1)); // [0,1,2]
var arr2 = [0,1,2,[3,4,5]],
arr2Copy = shadowCopy(arr2);
console.log(arr2); // [0,1,2,[3,4,5]]
console.log(arr2Copy); // [0,1,2,[3,4,5]]
arr2Copy[3][0] = 6;
console.log(arr2[3][0]); // 6
方式五:...实现的是对象第一层的深拷贝
const originArray = [1,2,3,4,5,[6,7,8]];
const originObj = {a:1,b:{bb:1}};
const cloneArray = [...originArray];
cloneArray[0] = 0;
cloneArray[5].push(9);
console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]
const cloneObj = {...originObj};
cloneObj.a = 2;
cloneObj.b.bb = 2;
console.log(originObj); // {a:1,b:{bb:2}}
总结
=:实现的是浅拷贝,仅拷贝对象的引用值。基础数据类型可以直接使用赋值
Javascript中数组和对象自带的拷贝方法都是"首层浅拷贝"
JSON.stringify实现的是深拷贝,但对目标对象有要求
若想真正的深拷贝,需自行递归
网友评论