写一个深克隆的方法,咱们须要掌握的知识点数组
js的类型分两种bash
由于有了引用类型,才有了深克隆和浅克隆的区别。闭包
浅克隆会对于原始类型,能够彻底复制,对于引用类型,只会复制它的引用,对其内部的值,不会复制。函数
深克隆不论对于原始类型,仍是引用类型,都会彻底复制。生成一个跟原来的对象,彻底没有关联的新对象。ui
写一个最简单的实现,只考虑简单对象的浅克隆spa
function clone(value) {
var cloneValue = {};
for (var prop in value) {
cloneValue[prop] = value[prop];
}
return cloneValue;
}
复制代码
写一个简单的实现,只考虑简单对象的深克隆prototype
function clone(value) {
var cloneValue = {};
for (var key in value) {
if(typeof value[key] === 'object') {
cloneValue[key] = clone(value[key]);
} else {
cloneValue[key] = value[key];
}
}
return cloneValue;
}
复制代码
在浅克隆的基础上,判断对象的属性值,是否仍是个对象,若是是,调用clone,造成递归,咱们的深克隆方法就实现啦。code
目前这个方法还不完善,增长咱们克隆对象的复杂度,不止是简单对象了,还要能克隆数组。对象
function type(value) {
return Object.prototype.toString.call(value).match(/\[object (.*?)\]/)[1];
}
function clone(value) {
var copyFunc = function(copiedValue){
for(var key in value) {
if(typeof value[key] === 'object') {
copiedValue[key] = clone(value[key]);
} else {
copiedValue[key] = value[key];
}
}
return copiedValue;
}
switch (type(value)) {
case 'Object': return copyFunc({});
case 'Array': return copyFunc([]);
default: return value;
}
}
复制代码
此次咱们除了clone方法,先写了一个type方法,利用Object.prototype.toString判断入参的类型。在clone方法里,咱们将上次的clone方法变成一个闭包函数copyFunc,如今的clone方法,先判断入参是对象仍是数组,再传入{}或者[]给copyFunc,利用for in语句既能够遍历对象,又能够遍历数组,完成克隆。递归
如今,咱们考虑更多的可克隆对象,除了对象、数组,还有Date、RegExp、这样的内置对象。
function _cloneRegExp(pattern){
return new RegExp(pattern.source, (
(pattern.global ? 'g' : '') +
(pattern.ignoreCase ? 'i' : '') +
(pattern.multiline ? 'm' : '') +
(pattern.sticky ? 'y' : '') +
(pattern.unicode ? 'u' : '') +
));
}
function clone(value) {
var copyFunc = function(copiedValue){
for(var key in value) {
if(typeof value[key] === 'object') {
copiedValue[key] = clone(value[key]);
} else {
copiedValue[key] = value[key];
}
}
return copiedValue;
}
switch (type(value)) {
case 'Object': return copyFunc({});
case 'Array': return copyFunc([]);
case 'Date': return new Date(value.valueOf());
case 'RegExp': return _cloneRegExp(value);
default: return value;
}
}
复制代码
只需在swith下添加两个case便可。写到这里,咱们的克隆方法基本完毕了,能够说这个实现,是我目前看过最清晰的深克隆实现了。
再考虑一种状况,就是对象的多个属性,引用同一个对象多状况。咱们但愿保证克隆的对象,一样能保持多个属性引用的是同一个克隆出来的对象。
var childObj = { key: 1 };
var obj = {
key1:childObj,
key2:childObj,
}
复制代码
好比上面这个obj对象,咱们要克隆它,能够用下面的深克隆实现。
function clone(value, refFrom = [], refTo = []) {
var copyFunc = function(copiedValue){
var len = refFrom.length;
var idx = 0;
while (idx < len) {
if (value === refFrom[idx]) {
return refTo[idx];
}
idx += 1;
}
refFrom[idx + 1] = value;
refTo[idx + 1] = copiedValue;
for(var key in value) {
if(typeof value[key] === 'object') {
copiedValue[key] = clone(value[key], refFrom, refTo);
} else {
copiedValue[key] = value[key];
}
}
return copiedValue;
}
switch (type(value)) {
case 'Object': return copyFunc({});
case 'Array': return copyFunc([]);
case 'Date': return new Date(value.valueOf());
case 'RegExp': return _cloneRegExp(value);
default: return value;
}
}
复制代码
这个版本的深克隆,就是ramda源码中对于克隆的实现,优雅又简洁。