什么是js深拷贝和浅拷贝?有哪些实现方式?
浅拷贝
浅拷贝其实我之前有文章具体讲过,不过没有提及这个名词罢了,例如:js内存空间及this关键词详解,这篇文章,里面讲到如下:
[code]var m = { a: 10, b: 20 } var n = m; n.a = 15; // 这时m.a的值是多少
m.a会输出15,因为这是浅拷贝,n和m指向的是同一个堆,对象复制只是复制的对象的引用。
深拷贝
深拷贝和上面浅拷贝不同,就是彻底copy一个对象,而不是copy对象的引用,例如,还是之前的例子,我们这么写:
[code]var m = { a: 10, b: 20 } var n = {a:m.a,b:m.b}; n.a = 15;
这次,我们再来输出m.a ,发现m.a的值还是10,并没有改变,m对象和n对象是虽然所有的值都是一样的,但是在堆里面,对应的不是同一个了,这个就是深拷贝。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
浅拷贝的实现方式
1、可以通过简单的赋值实现
类似上面的例子,当然,我们也可以封装一个简单的函数,如下:
[code]function simpleClone(initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj; } var obj = { a: "hello", b:{ a: "world", b: 21 }, c:["Bob", "Tom", "Jenny"], d:function() { alert("hello world"); } } var cloneObj = simpleClone(obj); console.log(cloneObj.b); console.log(cloneObj.c); console.log(cloneObj.d); cloneObj.b.a = "changed"; cloneObj.c = [1, 2, 3]; cloneObj.d = function() { alert("changed"); }; console.log(obj.b); console.log(obj.c); console.log(obj.d);
2、可以通过slice()方法实现
3、Object.assign()实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
[code]var obj = { a: {a: "hello", b: 21} }; var initalObj = Object.assign({}, obj); initalObj.a.a = "changed"; console.log(obj.a.a); // "changed"
注意:当object只有一层的时候,是深拷贝,例如如下:
[code]var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = Object.assign({}, obj1); obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
深拷贝的实现方式
1、对象只有一层的话可以使用上面的:Object.assign()函数
2、转成 JSON 再转回来
[code]var obj1 = { body: { a: 10 } }; var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.body.a = 20; console.log(obj1); // { body: { a: 10 } } <-- 沒被改到 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // false
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
可以封装如下函数
[code]var cloneObj = function(obj){ var str, newobj = obj.constructor === Array ? [] : {}; if(typeof obj !== 'object'){ return; } else if(window.JSON){ str = JSON.stringify(obj), //系列化对象 newobj = JSON.parse(str); //还原 } else { for(var i in obj){ newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]; } } return newobj; };
但有局限性,不能在后面接函数。
3、递归拷贝
[code]function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]); } else { obj[i] = prop; } } return obj; } var str = {}; var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);
4、使用Object.create()方法
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
[code]function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { obj[i] = prop; } } return obj; }
5、jquery
jquery 有提供一个$.extend可以用来做 Deep Copy。
[code]var $ = require('jquery'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = $.extend(true, {}, obj1); console.log(obj1.b.f === obj2.b.f); // false
6、lodash
另外一个很热门的函数库lodash,也有提供_.cloneDeep用来做 Deep Copy。
[code]var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // false
这个性能还不错,使用起来也很简单。
- 什么是单例模式?单例模式有哪些方式实现?写个例子。
- 什么是JS跨域请求?有几种方式可以实现?请简述其中某一种的实现原理?
- 继承有几种方式,分别是什么,想要实现继承可以使用哪些方法
- js 中多维数组的深拷贝的多种实现方式
- 什么是JS跨域请求?有几种方式可以实现?请简述其中某一种的实现原理?
- 设计模式用过哪些,应用场景是什么;单例模式有几种实现方式,代码怎么写?
- 面向对象的JS-私有成员变量实现方式
- JS实现继承的几种方式
- Node.js编写组件的三种实现方式
- 【JS】星级评分原理和实现(下集 第3章 第五种实现方式-下 下集 第4章 课程总结 )
- js实现类似于add(1)(2)(3)调用方式的方法
- C++浅拷贝的另一种实现方式
- js实现深拷贝和浅拷贝
- js 延迟加载的方式有哪些
- js图片延迟加载(Lazyload)三种实现方式
- qq第3方登录的JS实现方式记录
- JS继承的实现方式
- js实现页面跳转的几种方式
- 纯JS实现的3D标签云,不依赖不论什么第三方库,支持移动页面
- 用HTML/JS/PHP方式实现页面延时跳转的简单实例