一、需要知识点回顾
基本类型(值类型)和引用类型
(基本类型)值类型:Number,Boolean,String,undefined,null
引用类型:object,Arrary
二、基本类型和引用类型复制的区别
值类型:对值类型的复制操作,仅仅是对值的进行一份拷贝,复制与被复制的会指向两份不同的数据。
引用类型:引用类型复制的是地址。所以最后会发现,复制与被复制的最终会指向同一份数据。
例子:
// 基本类型
var a = 1;
var b = a;
a = 2;
console.log(a, b); // 2, 1 ,a b指向不同的数据
// 引用类型指向同一份数据
var a = {c: 1};
var b = a;
a.c = 2;
console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份数据
三、深拷贝和浅拷贝的区别
浅拷贝:只拷贝一层。
深拷贝:无限极拷贝。
四、深度拷贝的四个例子
方法一:
function clone(source){
if (!isObject(source)) return source;//参数校验更加优秀
var target={};
for(var i in source){
if(source.hasOwnProperty(source){
if(typeof source[i] === 'object'){ // Object.prototype.toString.call(source[i] === '[Object Object]'
target[i] = clone(source[i])
}else{
target[i] = source[i];
}
}
return target;
}
function isObject(obj){
return Object.prototype.toString.call(obj === '[Object Object]'
}
方法二:
function cloneJSON (source){
return JSON.parse(JSON.stringfy(source));
}
方法三:
function cloneLoop(x) {
const root = {};
// 栈
const loopList = [
{
parent: root,
key: undefined,
data: x,
}
];
while(loopList.length) {
// 深度优先
const node = loopList.pop();
const parent = node.parent;
const key = node.key;
const data = node.data;
// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
let res = parent;
if (typeof key !== 'undefined') {
res = parent[key] = {};
}
for(let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k],
});
} else {
res[k] = data[k];
}
}
}
}
return root;
}
方法四:
// 保持引用关系
function cloneForce(x) {
// =============
const uniqueList = []; // 用来去重
// =============
let root = {}
// 循环数组
const loopList = [
{
parent: root,
key: undefined,
data: x,
}
];
while(loopList.length) {
// 深度优先
const node = loopList.pop();
const parent = node.parent;
const key = node.key;
const data = node.data;
// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
let res = parent;
if (typeof key !== 'undefined') {
res = parent[key] = {};
}
// =============
// 数据已经存在
let uniqueData = find(uniqueList, data);
if (uniqueData) {
parent[key] = uniqueData.target;
break; // 中断本次循环
}
// 数据不存在
// 保存源数据,在拷贝数据中对应的引用
uniqueList.push({
source: data,
target: res,
});
// =============
for(let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k],
});
} else {
res[k] = data[k];
}
}
}
}
return root;
}
function find(arr, item) {
for(let i = 0; i < arr.length; i++) {
if (arr[i].source === item) {
return arr[i];
}
}
return null;
}