Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JS】浅拷贝和深拷贝 #15

Open
Dliling opened this issue Jun 4, 2020 · 0 comments
Open

【JS】浅拷贝和深拷贝 #15

Dliling opened this issue Jun 4, 2020 · 0 comments

Comments

@Dliling
Copy link
Owner

Dliling commented Jun 4, 2020

在说拷贝之前,先来简单说JS的数据类型~

  1. 原始类型:Boolean,Null,Undefined,Number,String,Symbol
  2. 引用类型:Object

这两种类型存储空间不通,原始类型是存放在栈内存中,而引用类型是存在堆内存中的,然后在栈内存中保存一个对堆内存中实际对象的引用。所以JS中对引用数据类型的操作都不是对象本身,而是操作对象的引用。
MacHi 2020-06-03 21-24-39
从上图可以看到,原始类型是直接存在栈内存中的,但是引用类型在栈内存中只是存了一个地址来表示对堆内存中的引用。

拷贝
原始类型如果拷贝的话,直接在栈内存中为新的变量分配一个新的内存地址。
引用类型的话,也会为新变量在栈内存中分配一个值,但这个值保存的依旧是一个地址,指向堆内存中的一个对象。所以如果拷贝引用类型的话,实际新旧变量都是相同的地址,指向的是同一个对象。修改其中一个变量时,同样会引起另一个变量的改变。
所以拷贝引用类型的时候,不能进行简单赋值了~
也就有了浅拷贝和深拷贝这两种方式~

浅拷贝
将内存中的某个对象复制一份,在内存中开辟一块新的空间,如果复制的对象是原始类型,则拷贝的是这个值本身,如果是引用类型,则拷贝的是对象地址,因此修改新对象会对原对象产生影响。
浅拷贝的函数就不再实现了,原始类型直接进行赋值,引用类型可以进行遍历赋值就行。

深拷贝
开辟一块新的空间,完整的复制一份,包括引用类型,拷贝的新对象与原对象无任何关系,不会相互影响。
深拷贝有多种方式,可以借助lodash,也可以借助jquery的extend~
下面主要介绍两种:

  1. JSON.parse(JSON.stringify(obj))
    先将对象转成字符串,再转成新的对象。
    简单易用,但是有一些局限性
    a)会抛弃对象的constructor。不管该对象原来的构造函数是什么,深拷贝之后,都会变成Object。
    b)能够正确处理的对象只有Number,String,Boolean,Array,即那些能够被JSON的数据结构,像时间戳、RegExp、函数无法通过这种方式拷贝。
  2. 递归拷贝
    浅拷贝+递归实现,浅拷贝时判断属性是否是对象,是对象进行递归。
// 是否是对象
function isObject(obj) {
	return typeof obj === 'object' && obj != null;
}
function cloneDeep(source) {

    if (!isObject(source)) return source; // 非对象返回自身
      
    var target = Array.isArray(source) ? [] : {};
    for(var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            if (isObject(source[key])) {
                target[key] = cloneDeep(source[key]); // 注意这里
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}

上面代码只是简单判断了对象和数组,如果对象只是由对象、数组和原始类型组成,用上面已经足够~
还有一位大佬写的很全面,可以移步

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant