【函數】深拷貝和淺拷貝


目錄:

1、深拷貝與淺拷貝

2、淺拷貝實現

3、深拷貝實現

 

深拷貝與淺拷貝

傳值與傳址

  相關筆記:https://www.cnblogs.com/xiaoxuStudy/p/12185177.html

  原始數據類型的拷貝是傳值,應用數據類型的拷貝是傳址。

深拷貝與淺拷貝

  因為原始類型的拷貝是傳值,所以對於原始數據類型並沒有深淺拷貝的區別。深淺拷貝都是對於引用數據類型而言的。

  深拷貝與淺拷貝的使用場景:1、都是復雜對象,即對象的屬性還是對象

  如果要賦值對象的所有屬性都不是引用類型的時候,可以使用淺拷貝,遍歷並復制。

   

淺拷貝實現

  淺拷貝只復制一層對象,當對象的屬性是引用類型時,實質復制的是其引用,當引用值指向發生改變時,也會跟着改變。

使用 for-in

  下面實現一個淺拷貝:

//實現淺拷貝
let shallowCopy = obj => {
    let rst = {};
    //遍歷對象
    for(let key in obj){
        //只復制本身擁有的(非繼承過來的)枚舉屬性
        if(obj.hasOwnProperty(key)){
            rst[key] =  obj[key];
        }
    }
    return rst;
}
let star = {
    name:'虞書欣',
    age : 20,
    //又是一個對象
    friend : {
        name : '孔雪兒'
    }
}
let otherStar = shallowCopy(star);
otherStar.name = '劉雨昕';
otherStar.age = '22';
otherStar.friend.name = '金子涵';
console.log( star );

 輸出:

{ name: '虞書欣', age: 20, friend: { name: '孔雪兒' } }

  上面創建一個 shallowCopy 函數,傳入一個對象作為參數,該函數遍歷該對象將該對象的屬性復制到一個空對象 rst 中,最后返回 rst 對象。創建一個star 對象, 注意這里 star 對象有一個屬性 friend, friend 是引用類型,將 star 作為參數傳給 shallowCopy 函數,shallowCopy 函數返回一個 rst 對象,otherStar 指向 rst 對象。這里看一下修改 otherStar 會不會影響到 star 。修改 otherStar 的 name 屬性、age 屬性跟 friend 屬性的對象的 name 屬性。輸出 star 發現 friend 屬性改變了,name屬性跟age屬性都沒有變。

  所以,要記得:淺拷貝只復制一層對象,當對象的屬性是引用類型時,實質復制的是其引用,當引用值指向發生改變時,也會跟着改變。

  用 Object.assign() 拷貝也是一樣。

 

使用 Object.assign( )

let xiaoxu = {
    name:'小許',
    info:{
        gender:'女',
        hobby:'sleep'
    }
}
let a = Object.assign( {}, xiaoxu );
a.name = "nana";
console.log( xiaoxu.name );         //沒變  //輸出:小許
a.info.gender = '男';
console.log( xiaoxu.info.gender );  //變了  //輸出:男

 

使用對象的擴展運算符

擴展運算符的 value 是原始數據類型的時候,是深拷貝。當 value 是引用類型的時候,是淺拷貝。

let xiaoxu = {
    name:'小許',
    info:{
        gender:'女',
        hobby:'sleep'
    }
}
let a = { ...xiaoxu };
a.name = "nana";
console.log( xiaoxu.name );         //沒變  //輸出:小許
a.info.gender = '男';
console.log( xiaoxu.info.gender );  //變了  //輸出:男

  

深拷貝實現

  深復制遞歸復制了所有層級。

使用 JSON.stringify()

注意:如果需要拷貝的是純的JSON數據,不需要循環引用,可以使用 JSON.stringify 實現。

let obj = {
    name : '小明',
    songs : ['想見你想見你想見你', '暮陽少年']
}

let obj1 = JSON.parse(JSON.stringify(obj));
obj1.name = '小華';
obj1.songs[0] = '飄';

let girl = [{
    name : '小許',
    colors : ['black','pink'],
    fn : function(){},
    age : undefined
}]

let boy = JSON.parse(JSON.stringify(girl));
console.log(boy);   //輸出:[ { name: '小許', colors: [ 'black', 'pink' ] } ]

 

使用遞歸

let deepClone = obj => {
    let newObj = Array.isArray(obj) ? [] : {};
    
    if( obj && typeof obj === 'object' ){
        for( let key in obj ){
            if( obj.hasOwnProperty(key) ){
                //如果對象的屬性是引用類型
                if( obj[key] && typeof obj[key] ){
                    newObj[key] = deepClone(obj[key]);
                }else{
                //如果對象的屬性不是引用類型,直接拷貝
                newObj[key] = obj[key];
                }
            }
        }
    }
    return newObj;
}
let xiaoxu = {
    name :'xiaoxu',
    idols : ['虞書欣','劉雨昕'],
    fn : function(){},
    age : undefined
}
let girl = deepClone(xiaoxu);
girl.name = 'nana';
girl.idols = ['林宥嘉','JonyJ'];
girl.fn = '親一口=3=';
girl.age = 20;
console.log(xiaoxu); 
console.log(girl);

 輸出:

 

混合模式 Mixin

不通過繼承去擴展方法

let mixin = {
    say(){
        console.log(`${this.name}在說話`);
    },
    sing(){
        console.log(`${this.name}在唱歌`);
    },
    run(){
        console.log(`${this.name}在跑步`);
    }
}

class Student{
    constructor(name){
        this.name = name;
    }
}

Object.assign( Student.prototype, mixin );
let student = new Student('小許');
student.sing();     //輸出:小許在唱歌

為什么要把 mixin 復制到 prototype 上?因為這樣子維護性好且減少內存占用。

 

Vue 的混入(Mixin)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{name}}..{{age}}</h1>
    </div>
    <script>
        Vue.mixin({
            data(){
                return{
                    name:'小許'
                }
            },
            methods:{
                say(){
                    console.log('hello');
                }
            }
        })
        new Vue({
            el:'#app',
            data(){
                return{
                    age:22
                }
            },
            mounted(){
                this.say();
            }
        })
    </script>
</body>
</html>

 

使用 pick

先使用命令 yarn add -D underscore 安裝 underscore 依賴

const _ = require(`underscore`);    //引進underscore
let obj = {
    name : '小許',
    age : 22
}
//返回一個 obj 的副本
let age = _.pick(obj, 'age');
console.log( age );     //輸出:{ age: 22 }
console.log( obj );     //輸出:{ name: '小許', age: 22 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM