对象的深浅拷贝
2018-12-28 20:44
309 查看
标题对象的深浅拷贝
在进行实例讲解之前,我们先下个给深浅拷贝下个定义,什么是深拷贝?什么是浅拷贝?
个人理解:
- 浅拷贝:针对指针的引用
- 深拷贝: 对值的引用
浅拷贝
先看🌰:
var obj = { a: 1, b: 2, }; var newObj = obj obj.a = 3 console.log(obj.a) // 3 console.log(newObj.a) // 3
深拷贝
var obj = { a: 1, b: 2, }; var newObj = {}; Object.keys(obj).map(item => { newObj[item] = obj[item]; }); obj.a = 666 console.log(obj.a) // 666 console.log(newObj.a) // 1
比较🌰1 和 例子2 的不同,这里将 1 (针对地址的引用) 称之为浅拷贝,2 (针对属性的拷贝) 称之为深拷贝,
区别也是显而易见的
案列:实现对象深拷贝的
var obj = { a: 1, b: 2, c: { sex: "man", options: { age: 22 } } }; var newObj = {}; function objDeep(newObj, obj) { Object.keys(obj).map(item => { if (obj[item] && !(obj[item] instanceof Object)) { newObj[item] = obj[item]; } else { newObj[item] = {}; arguments.callee(newObj[item], obj[item]); } }); } objDeep(newObj, obj); newObj.a = 999 console.log(obj.a) // 1 console.log(newObj.a) // 999
Object.assign()
既然提到对象的浅拷贝,就不得不提到 Object.assign()
MDN中的解释为:Object.assign() 方法用于将 所有可枚举属性的值 从一个或多个源对象复制到目标对象。它将返回目标对象。
举例:
Object.assign(target, source) var obj = { a: 1, b: 2 }; var copy = Object.assign({a: 3}, obj); console.log(copy); // { a: 1, b: 2 }
这里注意:源对象中的属性会代替目标对象的同名属性,这也就导致目标对象中的 {a: 3} 最终被替换为 {a: 1} 的结果
既然谈到了是可枚举属性,那我们再来看看不可枚举属性
对象的 数据属性 和 访问器属性 请自行查看 高层三, pdf 下载地址
// 通过 Object.create() 创建的对象,默认都是不可枚举的,需要手动设置 var obj = Object.create({foo: 1}, { // foo 是个继承属性。 a: { name: 'lilie' // a 是个不可枚举属性。 }, b: { name: 'lili', enumerable: true // b 是个自身可枚举属性。 } }); var copy = Object.assign({}, obj); console.log(copy); // { b: 'lili' }
为啥Object.assign() 是浅拷贝,我们再来看一个🌰:
var obj = { a: 1, b: [1,3],c: {name: 'name', age: 30} }; var copy = Object.assign({a: 3}, obj); obj.a = 999 console.log(obj.a) // 999 console.log(copy.a); // 1
写到这里,根据控制台打印结果,我反问自己,这不就是深拷贝么,事实上,你可以简单粗暴的这么理解,因为MDN解释很清楚了, Object.assign() 是对值的引用
- 到次为此,我们已经知道了两种关于对象深拷贝的方法
我们不妨再来一个骚操作:
var obj = { a: 1, b: [1,3],c: {name: 'name', age: 30} }; var copy = JSON.parse(JSON.stringify(obj)) // 先转化为字符串,在转化为json对象,相当于完完全全拷贝了一个副本 obj.a = 999 console.log(obj.a) // 999 console.log(copy.a); // 1
到这里,应该基本上差不多了
但是笔者我不忍心,Object.assign() 感觉很像对象的去重复,各位看官有木有,既然如此,我们顺便把 数组的去重 和 扁平化处理 的面试常遇到的代码顺便分享一下
一下关于 es6 的相关知识,如果不太了解,请移步至 es6 教程
数组的去重
let arr = [1, 5, 46, 79, 46, 78, 941, 1111, 1, 1, 1, 1, 1, 1, 1] let arr0 = [...new Set(arr)] // 通过 es6 的 set 结合 数组的扩展语法 console.log(arr0)
let arr1 = Array.from(new Set(arr)) // 通过 es6 的 set 结合 数组的Array.from console.log(arr1)
[1,3,4,5,1,2,3,3,4,8,90,3,0,5,4,0].filter(function(elem,index,Array){ return index === Array.indexOf(elem); }) console.log(r) let arr2 = [] // 土鳖的循环 for (let i = 0; i < arr.length; i++) { if (arr2.indexOf(arr[i]) === -1) arr2.push(arr[i]) } console.log(arr2)
//自定义添加方法去重复方法 可以是各种类型 var arr3= [0, 1, '1', true, 5, true, false, undefined, undefined, null, null]; if (!Array.prototype.unique) { Array.prototype.unique = function () { var hash = {}, result = [], type = '', item; for (var i = 0; i < this.length; i++) { item = this[i]; type = Object.prototype.toString.call(item);// 专门用来判断字符串的类型的 if ( !hash[item + type] ) { hash[item + type] = true; result.push(item); } } return result; }; } console.log(arr3.unique());
//对象的方法来找出先次数最多的数字 var adv={ init:function(){ var arr=[1,2,5,2,5,5,4,1,1,1,2,2,2]; function findNum(arr){ for(var i=0,hash=[];i<arr.length;i++){ hash[arr[i]]=0; for(var r=0;r<arr.length;r++){ if(arr[i]==arr[r]){ hash[arr[i]]++; } } } get(hash); //[4, 5, 1, 3] // 1 2 4 5 } function get(hash){ var arr=[]; for(var key in hash){ arr.push(hash[key]); } arr.sort(function(a,b){return b-a}); for(var key in hash){ if(hash[key]==arr[0]) console.log(key); } } findNum(arr); } }
扁平化处理
/** 数组相关的常用方法 */ const aboutArrayFun = { /** 扁平化处理 */ // 递归 flattenOne: arr => { var res = []; for (var i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { res = res.concat(flattenOne(arr[i])); } else { res.push(arr[i]); } } return res; }, // reduce flattenTwo: arr => { return arr.reduce(function(prev, item) { return prev.concat(Array.isArray(item) ? flattenTwo(item) : item); }, []); }, // 扩展运算符 flattenThree: arr => { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } return arr; }, }
关于对象的深浅拷贝就到这里,以上是个人的理解,其实并不难,只要抓住了重点
其它前端性能优化:
- 图片优化——质量与性能的博弈
- 浏览器缓存机制介绍与缓存策略剖析
- webpack 性能调优与 Gzip 原理
- 本地存储——从 Cookie 到 Web Storage、IndexDB
- CDN 的缓存与回源机制解析
- 服务端渲染的探索与实践
- 解锁浏览器背后的运行机制
- DOM 优化原理与基本实践
- Event Loop 与异步更新策略
- 回流(Reflow)与重绘(Repaint)
- Lazy-Load
- 事件的节流(throttle)与防抖(debounce
- 前端学习资料下载
- 技术体系分类
前端技术架构体系(没有链接的后续跟进):
- 调用堆栈
- 作用域闭包
- this全面解析
- 深浅拷贝的原理
- 原型prototype
- 事件机制、
- Event Loop
- Promise机制、
- async / await原理、
- 防抖/节流原理
- 模块化详解、
- es6重难点、
- 浏览器熏染原理、
- webpack配置(原理)
- 前端监控、
- 跨域和安全、
- 性能优化(参见上面性能优化相关)
- VirtualDom原理、
- Diff算法、
- 数据的双向绑定
- [TCP协议(三次握手、四次挥手)](https://blog.csdn.net/woleigequshawanyier/article/details/85223642
- DNS域名解析
其它相关
欢迎各位看官的批评和指正,共同学习和成长
希望该文章对您有帮助,你的 支持和鼓励会是我持续的动力
相关文章推荐
- 详解js中对象的深浅拷贝
- JS对象的深浅拷贝
- 【自】javascript对象的深浅拷贝浅析
- 对象的深浅拷贝方法
- 分析一下 原型模式的 UML 类图 。 复制对象, 深浅拷贝 月经贴 ,请回避
- javascript中对象的深浅拷贝
- java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))
- 关于:1.指针与对象;2.深浅拷贝(复制);3.可变与不可变对象;4.copy与mutableCopy的一些理解
- Javascript 对象复制(深浅拷贝)
- 对象深浅拷贝
- 实现数组和对象的深浅拷贝
- 对象深浅拷贝
- js 数组的深浅拷贝 js对象的深浅拷贝
- javascript 对象的深浅拷贝
- 对象的深浅拷贝
- js实现数组和对象的深浅拷贝
- 对象和数组的深浅拷贝
- 实现数组和对象的深浅拷贝
- python对象的深浅拷贝
- java的深浅拷贝与绕过构造函数获取对象的神奇之旅