【函数】深拷贝和浅拷贝


目录:

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