JavaScript 专题系列第六篇,讲解深浅拷贝的技巧和以及实现深浅拷贝的思路jquery
拷贝也是面试经典呐!git
若是是数组,咱们能够利用数组的一些方法好比:slice、concat 返回一个新数组的特性来实现拷贝。github
好比:面试
var arr = ['old', 1, true, null, undefined]; var new_arr = arr.concat(); new_arr[0] = 'new'; console.log(arr) // ["old", 1, true, null, undefined] console.log(new_arr) // ["new", 1, true, null, undefined]
用 slice 能够这样作:数组
var new_arr = arr.slice();
可是若是数组嵌套了对象或者数组的话,好比:函数
var arr = [{old: 'old'}, ['old']]; var new_arr = arr.concat(); arr[0].old = 'new'; arr[1][0] = 'new'; console.log(arr) // [{old: 'new'}, ['new']] console.log(new_arr) // [{old: 'new'}, ['new']]
咱们会发现,不管是新数组仍是旧数组都发生了变化,也就是说使用 concat 方法,克隆的并不完全。性能
若是数组元素是基本类型,就会拷贝一份,互不影响,而若是是对象或者数组,就会只拷贝对象和数组的引用,这样咱们不管在新旧数组进行了修改,二者都会发生变化。spa
咱们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指彻底的拷贝一个对象,即便嵌套了对象,二者也相互分离,修改一个对象的属性,也不会影响另外一个。code
因此咱们能够看出使用 concat 和 slice 是一种浅拷贝。对象
那如何深拷贝一个数组呢?这里介绍一个技巧,不只适用于数组还适用于对象!那就是:
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}] var new_arr = JSON.parse( JSON.stringify(arr) ); console.log(new_arr);
是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数,咱们作个试验:
var arr = [function(){ console.log(a) }, { b: function(){ console.log(b) } }] var new_arr = JSON.parse(JSON.stringify(arr)); console.log(new_arr);
咱们会发现 new_arr 变成了:
以上三个方法 concat、slice、JSON.stringify 都算是技巧类,能够根据实际项目状况选择使用,接下来咱们思考下如何实现一个对象或者数组的浅拷贝。
想想,好像很简单,遍历对象,而后把属性和属性值都放在一个新的对象不就行了~
嗯,就是这么简单,注意几个小点就能够了:
var shallowCopy = function(obj) { // 只拷贝对象 if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组仍是对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,而且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }
那如何实现一个深拷贝呢?提及来也好简单,咱们在拷贝的时候判断一下属性值的类型,若是是对象,咱们递归调用深拷贝函数不就行了~
var deepCopy = function(obj) { if (typeof obj !== 'object') return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
尽管使用深拷贝会彻底的克隆一个新对象,不会产生反作用,可是深拷贝由于使用递归,性能会不如浅拷贝,在开发中,仍是要根据实际状况进行选择。
难道到这里就结束了?是的。然而本篇其实是一个铺垫,咱们真正要看的是 jquery 的 extend 函数的实现,下一篇,咱们会讲一讲如何从零实现一个 jquery 的 extend 函数。
JavaScript专题系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript专题系列预计写二十篇左右,主要研究平常开发中一些功能点的实现,好比防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里、递归、乱序、排序等,特色是研(chao)究(xi) underscore 和 jQuery 的实现方式。
若是有错误或者不严谨的地方,请务必给予指正,十分感谢。若是喜欢或者有所启发,欢迎 star,对做者也是一种鼓励。