寫一個深克隆的方法,咱們須要掌握的知識點數組
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源碼中對於克隆的實現,優雅又簡潔。