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,對做者也是一種鼓勵。