关于JS实现深拷贝和浅拷贝的方式

 

深拷贝和浅拷贝是面试中经常出现的,主要考察对基本类型和引用类型的理解深度,本文主要给大家介绍了js实现深拷贝和浅拷贝的方式,需要的朋友可以参考下

说道数据拷贝就离不开数据类型,在JS中数据类型分为基本类型和引用类型 基本类型:

number, boolean,string,symbol,bigint,undefined,null

引用类型:

object 以及一些标准内置对象 Array、RegExp、String、Map、Set..

一. 基本类型数据拷贝

基本类型数据都是值类型,存储在栈内存中,每次赋值都是一次复制的过程

1

2

var a = 12;

var b = a;

二. 引用类型数据拷贝

1、浅拷贝

只拷贝对象的一层数据,再深处层次的引用类型value将只会拷贝引用 实现方式:

1.Object.assign() 和 ES6的拓展运算符

通常我们用 Object.assign() 方法来实现浅拷贝。 Object.assign()用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

let aa = {

    a: undefined,

    func: function(){console.log(1)},

    b:2,

    c: {x: 'xxx', xx: undefined},

    d: null,

    e: BigInt(100),

    f: Symbol('s')

}

let bb = Object.assign({}, aa) //  或者 let bb = {...aa}

aa.c.x = 111

console.log(bb)

// 第一层拷贝,遇到引用类型的值就会只拷贝引用

// {

//     a: undefined,

//     func: [Function: func],

//     b: 2,

//     c: { x: 111, xx: undefined },

//     d: null,

//     e: 100n,

//     f: Symbol(s)

// }

2.Object.create

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。Object.create(proto,[propertiesObject])接收两个参数一个是新创建对象的__proto__, 一个属性列表

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

let aa = {

    a: undefined,

    func: function(){console.log(1)},

    b:2,

    c: {x: 'xxx', xx: undefined},

}

let bb = Object.create(aa, Object.getOwnPropertyDescriptors(aa))

aa.c.x = 111

console.log(bb)

// 第一层拷贝,遇到引用类型的值就会只拷贝引用

// {

//     a: undefined,

//     func: [Function: func],

//     b: 2,

//     c: { x: 111, xx: undefined },

// }

2、深拷贝

在拷贝一个对象的时候为了避免修改对数据造成的影响,必须使用深拷贝。

实现方式:

1、 通过JSON.stringify()

1

2

3

4

var a = {a:1, b: 2}

var b = JSON.stringify(a);

a.a = 'a'

console.log(a, b) // { a: 'a', b: 2 } {"a":1,"b":2}

JSON.stringify()进行深拷贝有弊端: 忽略value为function, undefind, symbol, 并且在序列化BigInt时会抛出语法错误:TypeError: Do not know how to serialize a BigInt

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// 序列化function, undefind, symbol,忽略--------------------------------------------------------

    var obj = {

        a:function(){},

        b: undefined,

        c: null,

        d: Symbol('s'),

    }

    var objCopyed = JSON.stringify(obj);

     

    console.log("a:", a)

    // obj: { a: [Function: a], b: undefined, c: null, d: Symbol(s) }

    console.log("objCopyed:", objCopyed)

    // objCopyed: {"c":null}

// 序列化bigint抛出错误--------------------------------------------------------

    var obj = {

        a: 1,

        e: BigInt(9007199254740991)

    }

    var objCopyed = JSON.stringify(obj); // TypeError: Do not know how to serialize a BigInt

2、递归实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

const deepCopy = (obj) => {

    // 优化 把值类型复制方放到这里可以少一次deepCopy调用

    // if(!obj || typeof obj !== 'object') throw new Error("请传入非空对象")

    if(!obj || typeof obj !== 'object') return obj

    let result = {}

    if (Object.prototype.toString.call(obj).indexOf('Array') > 0) {

        result = []

    }

    // 另一种循环方式

    // for (let key in obj) {

    //     if (obj.hasOwnProperty(key)) {

    //        result[key] = deepClone(obj[key])

    //     }

    // }

    Object.keys(obj).forEach(key => {

        // 优化 把值类型复制方放到这里可以少一次deepCopy调用

        // if (obj[key] && typeof obj[key] === 'object') {

        //     result[key] = deepCopy(obj[key])

        // }else{

        //     result[key] = obj[key]

        // }

        result[key] = deepCopy(obj[key])

    });

    return result

}

let aa = {

    a: undefined,

    func: function(){console.log(1)},

    b:2,

    c: {x: 'xxx', xx: undefined},

    d: null,

    e: BigInt(100),

    f: Symbol('s')

}

let bb = deepCopy(aa)

aa.c.x = 123

aa.func = {}

console.log("aa", aa)

console.log("bb", bb)

// aa {

//     a: undefined,

//     func: {},

//     b: 2,

//     c: { x: 123, xx: undefined },

//     d: null,

//     e: 100n,

//     f: Symbol(s)

//  }

// bb {

//     a: undefined,

//     func: [Function: func],

//     b: 2,

//     c: { x: 'xxx', xx: undefined },

//     d: null,

//     e: 100n,

//     f: Symbol(s)

// }

手写深拷贝等这些工具方法,在实际生产中99.99%不会用到,毕竟有lodash、underscore这些方便的工具库呢?

到此这篇关于JS实现深拷贝和浅拷贝的方式详解的文章就介绍到这了,希望可以对你有所帮助!

转自:微点阅读   https://www.weidianyuedu.com

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值