淺拷貝:將一個對象自身的屬性拷貝給另外一個對象,若是源對象的屬性是基本類型則直接進行值賦值,若是是引用類型則進行引用賦值,也就是說只進行一層賦值。html
深拷貝:將一個對象自身的屬性拷貝給另外一個對象,若是源對象的屬性是基本類型則直接進行值賦值,若是是引用類型則複製這個引用類型,使得目標對象擁有一個引用類型且和這個源屬性如出一轍,而非是一個指針。數組
也就是說,深拷貝與淺拷貝最主要的區別在引用類型的拷貝上。函數
注意,引用賦值不是淺拷貝!! 引用賦值僅僅只是賦值個指針,兩個變量都指向同一內存區域,而淺拷貝是使得兩個變量分別指向不一樣的內存區域測試
若是不懂,能夠參考這裏 一個小姐姐的博客prototype
以上不是重點...指針
function shallowCopy(source){ var target=source instanceof Array ? [] : {}; for(var i in source){ if(source.hasOwnProperty(i)){ target[i]=source[i]; } } return target; } // 測試 var obj={a:1,b:[1,2,3],c:function(){console.log('i am c')}} var tar=shallowCopy(obj) tar.c() // "i am c" obj.a=5 obj.a // 5 tar.a // 1 obj.b[0]=10 obj.b // [10, 2, 3] tar.b // [10, 2, 3] var arr=[1,2,[4,5,6]] var newArr=shallowCopy(arr) newArr // [1, 2, [4,5,6]] arr[0]=10 arr // [10, 2, [4,5,6]] newArr // [1, 2, [4,5,6]] arr[2][0]=10 arr // [1, 2, [10,5,6]] newArr // [1, 2, [10,5,6]]
Object.assigncode
var obj={a:1,b:[1,2,3],c:function(){console.log('i am c')}} var tar={}; Object.assign(tar,obj);
固然這個方法只適合於對象類型,若是是數組可使用slice和concat方法htm
Array.prototype.slice對象
var arr=[1,2,[3,4]]; var newArr=arr.slice(0);
Array.prototype.concatblog
var arr=[1,2,[3,4]]; var newArr=arr.concat();
測試同上(assign用對象測試、slice concat用數組測試),結合淺拷貝深拷貝的概念來理解效果更佳
var obj={a:1,b:[1,2,3],c:function(){console.log('i am c')}} var tar=JSON.parse(JSON.stringify(obj)); // 測試 obj.a=5 obj.a // 5 tar.a // 1 obj.b[0]=10 obj.b // [10, 2, 3] tar.b // [1, 2, 3] tar.c() // Uncaught TypeError: tar.c is not a function
能夠看到,不管是基本類型仍是引用類型,兩個對象的相同屬性(屬性名相同的屬性)之間並無關係了,但tar.c()
報錯了,咱們打印看一下tar有什麼console.log(tar) // {a: 1, b: Array(3)}
能夠看到c方法沒了,這是和JSON的語法有關,JSON 並不支持函數類型的數據。這也就是這種方法的最大缺陷。
仔細一看,這並不是黑科技,反而卻是有很大缺陷,不過很好用、效率高,只是在使用前須要稍加註意是否有函數類型的數據罷了。
深拷貝與淺拷貝相比不就是多拷貝幾層的事嘛,這不就是遞歸常乾的事嘛。因此咱們就想,在每次拷貝時都判斷下,該屬性是不是引用類型,若是是咱們再遞歸調用拷貝方法,不然直接進行值賦值。
function deepCopy(obj,tar){ var tar = tar || {}; for(var i in obj){ if(typeof obj[i] === 'object'){ if(obj[i].constructor === Array){ tar[i] =[]; }else{ tar[i] = {}; } deepCopy(obj[i],tar[i]); } else{ tar[i] = obj[i]; } } return tar; } // 使用 var obj={a:1,b:[1,2,3],c:function(){console.log('i am c')}}; var tar={}; deepCopy(obj,tar); console.log(tar);
測試同上,你會驚喜的發現第一個方法中的函數bug沒了
你看出來函數是怎樣進行拷貝的了嗎?很簡單,typeof
運算符的操做對象是一個函數時,獲得的是 "function"
因此在循環裏第一個if判斷那爲false 因此走else分支,在tar[i] = obj[i]
這裏,函數是進行引用賦值的,若是再造一個相同的函數不是不能夠,只是不符合思想罷了,函數佔用堆內存,若是能夠共用固然是最好的選擇。
固然這個方法仍是有些許不足之處,不夠已經很棒了
這就須要去讀一些好的源碼了,好比Zepto、JQuery中extend方法的實現
現學現賣,若有不足請指出...