javascript數組在使用時,時常會遇到數組備份的情況,之後對數組做些修改,再同原數組進行比對,查看數組的變化,這裏就涉及到一個數組拷貝的問題。
淺拷貝只複製一層對象的屬性;深拷貝遞歸複製了所有層級。
數組的拷貝,通常可以使用一個新的數組,指向現有數組
var arr = [el1, el2, el3...];
var arr2 = arr;
這種寫法,待arr2做改變時,我們查看arr會同步做修改
ex
var arr = ['liuche', 'zhouyafu', 'huoqubing', 'weiqing'];
var arr2 = arr;
arr2.push('liguang');
alert(arr); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'
alert(arr2); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'
這裏我們看到,待修改數組arr2時,arr同時做了改變,這顯然不是我們想要的結果。
示例中,這種直接將數組引用複製的方式就是淺拷貝。
那我們想要對數組進行備份的話,該如何操作呢,可以藉助於Array對象的slice()方法和concat()方法。
slice方法
slice() 方法可從已有的數組中返回選定的元素。
arrayObject.slice(start,end)
其中:
start,必需。規定從何處開始選取。如果是負數,那麼它規定從數組尾部開始算起的位置,從0開始。也就是說,-1 指最後一個元素,-2 指倒數第二個元素,以此類推。
end,可選。規定從何處結束選取。該參數是數組片斷結束處的數組下標。如果沒有指定該參數,那麼切分的數組包含從 start 到數組結束的所有元素。如果這個參數是負數,那麼它規定的是從數組尾部開始算起的元素。
slice方法返回一個新的數組,包含從 start 到 end (不包括該元素)的 arrayObject 中的元素。
若start爲0,end 缺省,則相當於截取了整個數組的元素值,即我們這裏要說的數組拷貝。
ex2
var arr = ['liuche', 'zhouyafu', 'huoqubing', 'weiqing'];
var arr2 = arr.slice(0);
arr2.push('liguang');
alert(arr); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing'
alert(arr2); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'
但是,如果遇到多維數組,slice方法並不奏效
ex3
var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.slice(0);
arr2.push('liguang');
alert(arr); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao,liguang
和
ex4
var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.slice(0);
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
上面兩個示例中,ex3中,arr2修改後,arr並未跟着一起修改,因爲arr2的修改,是給arr2新增了arr[3]元素;但是ex4中,arr2修改後,arr跟着一起修改了,原因在於arr中arr[0] 元素是個數組對象,並非單的數值。
concat方法
concat() 方法用於連接兩個或多個數組。
該方法不會改變現有的數組,而僅僅會返回被連接數組的一個副本。
arrayObject.concat(arrayX,arrayX,......,arrayX)
其中
arrayX,必需。該參數可以是具體的值,也可以是數組對象。可以是任意多個。
concat方法返回一個新的數組。該數組是通過把所有 arrayX 參數添加到 arrayObject 中生成的。如果要進行 concat() 操作的參數是數組,那麼添加的是數組中的元素,而不是數組。
使用concat() 方法時,若arrayX爲空,則相當於原數組與一個空數組拼接,即返回原數組,做到原數組的拷貝。
那使用concat方法再來看看剛纔的示例
ex5
var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.concat();
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
結果同ex4相同,並未得到我們想要的結果
實在無解之際,諮詢了下一個專職做前端的同事,瞭解到一個萬能的JS拷貝方法,無論是數組還是對象均可以實現深拷貝
JSON.parse(JSON.stringify(arr));
這個方法其實比較簡單,先把所有的對象屬性解析爲簡單數值,再將數值拼接解析爲JS對象。
看之前的例子
ex6
var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = JSON.parse(JSON.stringify(arr));
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
解決上面的問題。
經過上面的例子和分析,可以看出來,簡單數組的拷貝可以通過slice方法和concat方法來實現,對於多維數組的實現,必須通過JSON.parse(JSON.stringify(obj))方法來實現。初次學習,有不當地方還望大家批評斧正。謝謝。