JavaScript中的數組拷貝

 

拷貝分爲淺拷貝和深拷貝,在JavaScript中能夠實現這兩種拷貝的方式也是多種多樣。以下是一維數組實現深拷貝和淺拷貝的各種方式。

一、淺拷貝

1、賦值

賦值是最直接的一種淺拷貝。

    let arr3 = [1,2,3]
    let arr4 = arr3
    arr4[0] = 11
    console.log('arr3:',arr3); // [11,2,3]

 2、copyWithin()方法——ES6新增

    let arr3 = [1, 2, 3]
    let arr4 = arr3.copyWithin(0,0)
    arr4[0] = 11
    console.log('修改arr4:', arr4); // 11,2,3
    console.log('arr3:', arr3); // 11,2,3

二、深拷貝(針對一維純值數組)

1、concat() 方法

concat() 方法用於連接兩個或多個數組。該方法不會改變現有的數組,而僅僅會返回被連接數組的一個副本。其參數可以是具體的值,也可以是數組對象。可以是任意多個。

arrayObject.concat(arrayX,arrayX,......,arrayX)
參數 描述
arrayX 必需。該參數可以是具體的值,也可以是數組對象。可以是任意多個。

利用concat()方法可以得到一個深拷貝的數組副本。

    let arr3 = [1,2,3]
    let arr4 = arr3.concat();
    arr4[0] = 11
    console.log('修改arr4:',arr4); //  11,2,3
    console.log('arr3:',arr3);  // 1,2,3

2、slice()方法

slice() 方法可從已有的數組中返回選定的元素。返回一個新的數組,包含從 start 到 end (不包括該元素)的 arrayObject 中的元素。該方法並不會修改數組,而是返回一個子數組。

arrayObject.slice(start,end)
參數 描述
start 必需。規定從何處開始選取。如果是負數,那麼它規定從數組尾部開始算起的位置。也就是說,-1 指最後一個元素,-2 指倒數第二個元素,以此類推。
end 可選。規定從何處結束選取。該參數是數組片斷結束處的數組下標。如果沒有指定該參數,那麼切分的數組包含從 start 到數組結束的所有元素。如果這個參數是負數,那麼它規定的是從數組尾部開始算起的元素。

利用slice()方法可以得到一個深拷貝的數組副本。

    let arr3 = [1,2,3]
    let arr4 = arr3.slice()
    arr4[0] = 11
    console.log('修改arr4:',arr4); // 11,2,3
    console.log('arr3:',arr3);  // 1,2,3

3、序列化和反序列化方法

利用JSON.parse和JSON.stringify組合得到一個深拷貝的數組副本。

    let arr3 = [1,2,3]
    let arr4 = JSON.parse(JSON.stringify(arr3))  
    arr4[0] = 11
    console.log('修改arr4:',arr4); // 11,2,3
    console.log('arr3:',arr3);  // 1,2,3

注:此方法適用於Oject的深度拷貝,因爲Array屬於Oject類型,所以也適用於此處;需要注意的是:作爲Oject的深度拷貝時,要複製的function會直接消失,所以這個方法只能用在單純只有數據的對象。

4、擴展運算符——ES6新增

ES6新增的擴展運算符可以方便的實現數組的深拷貝(克隆)。

    let arr3 = [1,2,3]
    let arr4 = [...arr3]
    arr4[0] = 11
    console.log('修改arr4:',arr4);   // 11,2,3
    console.log('arr3:',arr3);   // 1,2,3
    let arr3 = [1,2,3]
    let [...arr4] = arr3
    arr4[0] = 11
    console.log('修改arr4:',arr4);
    console.log('arr3:',arr3);

5、Array.from——ES6新增

    let arr1 = [1,2,3]
    let arr2 = Array.from(arr1)
    arr2[0] = 11
    console.log('修改learr2');
    console.log('arr1是否變化',arr1); // 驗證結果:Array.from返回的是一個深度拷貝數組

6、map()方法

map() 方法返回一個新數組,數組中的元素爲原始數組元素調用函數處理後的值。

map() 方法按照原始數組元素順序依次處理元素。

注意: map() 不會對空數組進行檢測。 map() 不會改變原始數組。

array.map(function(currentValue,index,arr), thisValue)
參數 描述
function(currentValue, index,arr) 必須。函數,數組中的每個元素都會執行這個函數
函數參數:
參數 描述
currentValue 必須。當前元素的值
index 可選。當前元素的索引值
arr 可選。當前元素屬於的數組對象
thisValue 可選。對象作爲該執行回調時使用,傳遞給函數,用作 "this" 的值。
如果省略了 thisValue,或者傳入 null、undefined,那麼回調函數的 this 爲全局對象。
    let arr3 = [1,2,3]
    let arr4 = arr3.map(item => item)
    arr4[0] = 11
    console.log('修改arr4:',arr4);  // 11,2,3
    console.log('arr3:',arr3);  // 1,2,3

7、Object.assign()方法——ES6新增

Object.assign方法用於對象的合併,將源對象(source)的所有可枚舉屬性,複製到目標對象(target)。

    let arr3 = [1,2,3]
    let arr4 = []
    Object.assign(arr4,arr3)
    arr4[0] = 11
    console.log('修改arr4:',arr4); // 11,2,3
    console.log('arr3:',arr3);   // 1,2,3

注意:Object.assign()方法實行的是淺拷貝,而不是深拷貝。如果數組中的項是一個對象,那麼目標數組中的該項拷貝得到的是這個對象的引用。

    let arr3 = [{name:'aaa'},2,3]
    let arr4 = []
    Object.assign(arr4,arr3)
    arr4[0].name = 11
    console.log('修改arr4:',arr4);  // {name:11},2,3
    console.log('arr3:',arr3);  // {name:11},2,3

8、擴展原型鏈

Array.prototype.clone = function () {
        let arr = []
        for (let i = 0, len = this.length; i < len; i++) {
            arr.push(this[i])
        }

        return arr
    }
    let arr3 = [1, 2, 3]
    let arr4 = arr3.clone()
    arr4[0] = 11
    console.log('修改arr4:', arr4); // 11,2,3
    console.log('arr3:', arr3);  // 1,2,3

 9、filter方法

filter() 方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素。

注意: filter() 不會對空數組進行檢測。filter() 不會改變原始數組。

array.filter(function(currentValue,index,arr), thisValue)
參數 描述
function(currentValue, index,arr) 必須。函數,數組中的每個元素都會執行這個函數。返回true表示保留該元素(通過測試),false則不保留
函數參數:
參數 描述
currentValue 必須。當前元素的值
index 可選。當前元素的索引值
arr 可選。當前元素屬於的數組對象
thisValue 可選。對象作爲該執行回調時使用,傳遞給函數,用作 "this" 的值。
如果省略了 thisValue ,"this" 的值爲 "undefined"

 返回值:返回數組,包含了符合條件的所有元素。如果沒有符合條件的元素則返回空數組。

    let arr3 = [1, 2, 3]
    let arr4 = arr3.filter(item => true)
    arr4[0] = 11
    console.log('修改arr4:', arr4); // 11,2,3
    console.log('arr3:', arr3);  // 1,2,3

總結

以上各種深拷貝方式只針對一維並且每一項值爲數值和字符串的數組。多維數組或者一維但包含對象的數組除了第三種方式外,其他方式並不能實行深拷貝,實行的是淺拷貝。

三、多維數組的深拷貝

function deepcopy(obj) {
            let out = [],len = obj.length;
            for (let i = 0; i < len; i++) {
                if (obj[i] instanceof Array){
                    out[i] = deepcopy(obj[i]);
                } else {
                    out[i] = obj[i];
                } 
            }
            return out;
        }

另一種方式:採用上面的第三種方式:序列化和反序列化結合實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章