javascript实现引用数据类型的深拷贝和浅拷贝详解
关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html
深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点。深浅拷贝的原型都是Object,深拷贝指向的堆内存不一样,浅拷贝指向的堆内存一样):
如何区分深拷贝与浅拷贝,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B没有发生变化,说明是深拷贝。如果B也跟着发生了变化,说明是浅拷贝。
let obj = { name: "jin", arr: ["red","blue","black"]}; let obj1 = {}; Object.defineProperties(obj1, Object.getOwnPropertyDescriptors(obj)); // 深拷贝 Object.assign(obj1, obj); // 深拷贝 obj1 = JSON.parse(JSON.stringify(obj)); // 深拷贝
obj1 = { ...obj }; // 深拷贝 obj1 = deepCopy(obj); // 使用到深拷贝函数 obj1 = obj; // 浅拷贝 obj1 = Object.assign(obj); // 浅拷贝
下面是deepCopy()深拷贝函数,其中使用到了判断变量的类型函数
// 判断变量的类型 function getType(obj){ let str = Object.prototype.toString.call(obj); // 检测基本类型值,引用类型值的类型 let map = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regExp', '[object Undefined]': 'unfefined', '[object Null]': 'null', '[object Object]': 'object' }; if(obj instanceof Element){ return 'element'; } return map[str]; } // 深拷贝函数 function deepCopy(p){ let obj; let str = getType(p); if(str === 'array'){ obj = []; for(let i=0;i<p.length;i++){ // obj.push(p[i]); // 不能这样写,因为会把array的堆内存也会复制过去 obj.push(arguments.callee(p[i])); //回调自己 } }else if(str === 'object'){ obj = {}; for(let i in p){ // obj[i] = p[i]; // 不能这样写,因为会把object的堆内存也会复制过去 obj[i] = arguments.callee(p[i]); //回调自己 } } else { return p; } return obj; }
需要特别注意的是,使用JSON.parse(JSON.stringify(x))不是一个很好的选择,也算是它们的坑吧:
对象是由构造函数生成的:会丢弃对象的constructor,因为JSON.stringify()只能序列化对象的可枚举的自有属性
时间对象:变成字符串
RegExp,Error对象:变成空对象
函数,undefined:会被丢失
NaN,Infinity和-Infinity:变成null
function Person(name){ this.name = name; } var person = new Person('liai'); var test = { name: 'jin', person: person, //对象是由构造函数生成的:会丢弃对象的constructor date: new Date(), //序列化后返回是字符串,不是时间对象 regexp: new RegExp('\\w+'), //序列化后返回空对象:{} err: new Error(), //序列化后返回空对象:{} fun: function(){}, //序列化后会丢失 undef: undefined, //序列化后会丢失 nun: NaN, //序列化后返回null }; console.log(test); console.log(JSON.parse(JSON.stringify(test)));