JavaScript中的淺拷貝

1.什麼是淺拷貝

例如:根據原始A對象淺拷貝一個新的B對象出來

淺拷貝就是創建一個新對象B,這個對象B有着原始對象A屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是A對象的基本類型的值;如果屬性是引用類型,拷貝的就是A對象的內存(引用)地址 ,所以如果其中一個對象改變了這個地址,就會影響到另一個對象。

淺拷貝只是解決了第一層的拷貝問題,拷貝第一層的基本類型值,以及第一層的引用類型地址,並沒有遞歸拷貝第二層以後的屬性。

2.淺拷貝使用方式

1.Object.assign()

Object.assign() 方法用於將所有可枚舉屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。

如何判斷一個屬性是否可枚舉?Object.keys() 可以判斷,它返回一個包含所有給定對象自身可枚舉屬性名稱的數組,如果返回的是空數組代表沒有可枚舉的屬性。例如:Number, Boolean, Symbol …是不可枚舉的

案例1:根據原始A對象淺拷貝一個新的B對象出來

// 1.Object.assign()  淺拷貝
let A = {
  name:'liujun',
  age:25,
  job:{
    name:'web',
    year:4
  }
}
console.log(A) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }
// 1.1 根據原始A對象淺拷貝一個新的B對象出來
let B = Object.assign({},A)
console.log(B) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }

// 1.2 修改A對象的兩個name屬性。發現B對象的job中的name屬性也跟着改動了,說明B對象拷貝A對象job的引用地址
A.name = '劉軍'
A.job.name = '前端開發'
console.log('--------------------------------')
console.log(A) // { name: '劉軍', age: 25, job: { name: '前端開發', year: 4 } }
console.log(B) // { name: 'liujun', age: 25, job: { name: '前端開發', year: 4 } }

總結:只是解決了第一層的拷貝問題,拷貝第一層的基本類型值,以及第一層的引用類型地址

引用類型有 : Object Array Function Date RegExp …

案例2:根據原始 A1 和 A2 淺拷貝一個新的B對象出來

    // 1.Object.assign()  淺拷貝
    let A1 = 'LJ'
    let A2 = 25
    console.log(Object.keys(A1)) // [ '0', '1' ] 可枚舉,拷貝成功
    console.log(Object.keys(A2)) // [] 不可枚舉,拷貝失敗

    // 1.1根據原始A1和A2淺拷貝一個新的B對象出來
    let B = Object.assign({},A1, A2)
    console.log(B) // { '0': 'L', '1': 'J' }

總結:Object.assign() 方法用於將所有可枚舉屬性的值從一個或多個源對象複製到目標對象

Number, Boolean, Symbol RegExp …是不可枚舉的, 直接傳遞到 assign 中拷貝會失敗,但是可以把它們封裝到對象中傳遞即可以拷貝成功。

2.ES6的{…}語法

案例1:根據原始A對象淺拷貝一個新的B對象出來

// 1.Object.assign()  淺拷貝
let A = {
  name:'liujun',
  age:25,
  job:{
    name:'web',
    year:4
  }
}
console.log(A) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }
// 1.1 根據原始A對象淺拷貝一個新的B對象出來
let B = {...A}  // 這個與Object.assign({},A)的功能一樣
console.log(B) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }

// 1.2 修改A對象的兩個name屬性。發現B對象的job中的name屬性也跟着改動了,說明B對象拷貝A對象job的引用地址
A.name = '劉軍'
A.job.name = '前端開發'
console.log('--------------------------------')
console.log(A) // { name: '劉軍', age: 25, job: { name: '前端開發', year: 4 } }
console.log(B) // { name: 'liujun', age: 25, job: { name: '前端開發', year: 4 } }

總結:只是解決了第一層的拷貝問題,拷貝第一層的基本類型值,以及第一層的引用類型地址。與Object.assign( {}, X ) 的功能一樣

引用類型有 : Object Array Function Date RegExp …

3.[].slice()

案例1:根據原始A數組淺拷貝一個新的B數組出來

  // 1.使用 [].slice() 淺拷貝
  let A =[
      'arr1',
      [
        'java',
        'web'
      ]
    ]
  console.log(A) // [ 'arr1', [ 'java', 'web' ] ]
  // 1.1根據原始A對象淺拷貝一個新的B對象出來
  let B = A.slice()
  console.log(B) // [ 'arr1', [ 'java', 'web' ] ]

 // 1.2 修改A數組[1][1]的值。發現B數組的中[1][1]的值也跟着改動,說明B數組中二維數組拷貝的是引用地址
  A[0] = '劉軍'
  A[1][1] = '前端開發' 
  console.log('--------------------------------')
  console.log(A) // [ '劉軍', [ 'java', '前端開發' ] ]
  console.log(B) // [ 'arr1', [ 'java', '前端開發' ] ]

總結:只是解決了第一層的拷貝問題,拷貝第一層的基本類型值,以及第一層的引用類型地址

4.[].concat()

案例1:根據原始A數組淺拷貝一個新的B數組出來

  // 1.使用 [].slice() 淺拷貝
  let A =[
      'arr1',
      [
        'java',
        'web'
      ]
    ]
  console.log(A) // [ 'arr1', [ 'java', 'web' ] ]
  // 1.1根據原始A對象淺拷貝一個新的B對象出來
  let B = [].concat(A)
  console.log(B) // [ 'arr1', [ 'java', 'web' ] ]

 // 1.2 修改A數組[1][1]的值。發現B數組的中[1][1]的值也跟着改動,說明B數組中二維數組拷貝的是引用地址
  A[0] = '劉軍'
  A[1][1] = '前端開發' 
  console.log('--------------------------------')
  console.log(A) // [ '劉軍', [ 'java', '前端開發' ] ]
  console.log(B) // [ 'arr1', [ 'java', '前端開發' ] ]

總結:只是解決了第一層的拷貝問題,拷貝第一層的基本類型值,以及第一層的引用類型地址

5.編寫淺拷貝函數

// 1.簡單淺拷貝函數
function shallowCopy(source) {
    var target = {};
    for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
        }
    }
    return target;
}

// 2.使用方法
let B = shallowCopy(A)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章