最简单的利用 = 赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着 cloneArray 和 cloneObj 改变,originArray 和 originObj 也随着发生了变化。
const originArray = [1, 2, 3, 4, 5];
const originObj = {a: 'a', b: 'b', c: [1, 2, 3], d: {dd: 'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
var user1 = {
name: "椿生",
age: 20,
hobbies: ['music', 'pingpong']
};
var user2 = Object.assign({}, user1);
console.log(user1); //{name: "椿生", age: 20, hobbies: ['music', 'pingpong']}
console.log(user2); //{name: '椿生', age: 20, hobbies: ['music', 'pingpong']}
// Object 单层对象深拷贝
user1.name = "Sakura";
console.log(user1); //{name: 'Sakura', age: 20, hobbies: ['music', 'pingpong']}
console.log(user2); //{name: '椿生', age: 20, hobbies: ['music', 'pingpong']}
// Object 多层对象浅拷贝
user1.hobbies[0] = "League of Legends";
console.log(user1); //{name: 'Sakura', age: 20, hobbies: ['League of Legends', 'pingpong']}
console.log(user2); //{name: '椿生', age: 20, hobbies: ['League of Legends', 'pingpong']}
var user1 = {
name: "椿生",
like: {
singer: "Eason Chan",
sport: "pingpong",
},
};
var user2 = {...user1};
console.log(user1); // {name: '椿生', like: {singer: 'Eason Chan', sport: 'pingpong'}}
console.log(user2); // {name: '椿生', like: {singer: 'Eason Chan', sport: 'pingpong'}}
user1.name = "Sakura";
console.log(user1); // {name: 'Sakura', like: {singer: 'Eason Chan', sport: 'pingpong'}}
console.log(user2); // {name: '椿生', like: {singer: 'Eason Chan', sport: 'pingpong'}}
user1.like.singer = "Anita Mui";
console.log(user1); // {name: 'Sakura', like: {singer: 'Anita Mui', sport: 'pingpong'}}
console.log(user2); // {name: '椿生', like: {singer: 'Anita Mui', sport: 'pingpong'}}
// 结论:... 实现的是对象第一层的深拷贝。更深层拷贝的是其引用值,为浅拷贝。
const originArray = [1, [1, 2, 3], {a: 1}];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
// originArray 中含有数组 [1,2,3] 和对象 {a:1},如果我们直接修改数组和对象,不会影响 originArray,
// 但是我们修改数组 [1,2,3] 或对象 {a:1} 时,发现 originArray 也发生了变化。
// 结论:concat 只是对数组的第一层进行深拷贝。
const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
// 结论:slice 只是对数组的第一层进行深拷贝
$.extend(deep, target, object1, object2, ....)
通过这个方法就可以实现深浅拷贝。各个参数的说明如下:
var user = {
name: "法医",
age: 18,
like: {
eat: "面条",
sport: "篮球",
},
};
var target = {};
$.extend(target, user);
target.name = "前端猎手";
console.log(user); //{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
console.log(target); //{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
实现思想:通过递归思维,遍历所需进行深拷贝的对象,直到里边的都是基本数据类型,然后再进行赋值,就是深度拷贝。
能实现普通对象(function, Symbol(), undefined 这三种除外)的深拷贝;而实现function, Symbol(), undefined 这三种时,会造成数据丢失。
let test = {
fun: function(){},
abc: undefined,
sym: Symbol(),
def: 'aaa',
fn: function(){},
};
console.log(JSON.parse(JSON.stringify(test))); // {def: 'aaa'}
var user = {
name: "法医",
age: 18,
like: {
eat: "面条",
sport: "篮球",
},
};
var target = {};
$.extend(true,target, user);
target.like.eat = "米饭";
console.log(user); //{name: '法医', like: {eat: '面条', sport: '篮球'}}
console.log(target); //{name: '法医', like: {eat: '米饭', sport: '篮球'}}
//定义检测数据类型的功能函数
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function deepClone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result, targetType = checkedType(target) //这里的意思是相当于let result; let targetType = checkedType(target);
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === 'Object' || checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = deepClone(value)
} else { //获取到value值是基本的数据类型或者是函数。
result[i] = value;
}
}
return result
}
// 深拷贝:对对象内部进行深拷贝,支持 Array、Date、RegExp、DOM
function deepCopy(params) {
// 如果不是对象则退出(可停止递归)
if (typeof params !== 'object') return;
// 深拷贝初始值:对象/数组
let newObj = (params instanceof Array) ? [] : {};
// 使用 for-in 循环对象属性(包括原型链上的属性)
for (let i in params) {
// 只访问对象自身属性
if (params.hasOwnProperty(i)) {
// 当前属性还未存在于新对象中时
if (!(i in newObj)) {
if (params[i] instanceof Date) {
// 判断日期类型
newObj[i] = new Date(params[i].getTime());
} else if (params[i] instanceof RegExp) {
// 判断正则类型
newObj[i] = new RegExp(params[i]);
} else if ((typeof params[i] === 'object') && params[i].nodeType === 1) {
// 判断 DOM 元素节点
let domEle = document.getElementsByTagName(params[i].nodeName)[0];
newObj[i] = domEle.cloneNode(true);
} else {
// 当元素属于对象(排除 Date、RegExp、DOM)类型时递归拷贝
newObj[i] = (typeof params[i] === 'object') ? deepCopy(params[i]) : params[i];
}
}
}
}
return newObj;
}