var obj = {
name:'Lee',
hobby:['吃','睡']
}
引用赋值:
赋值得到的对象和原对象引用的是堆内存中的同一个地址,指向的是同一个对象。所以改变赋值后对象的基本类型值和引用类型值,原对象的基本类型值和引用类型值也会被改变。
var obj1 = obj
obj1.name = 'Mary'
obj1.hobby[1] = '买'
console.log(obj)
改变 obj1 的 name 属性和 hobby 属性的第一个元素,可以看到 obj 的值也被改变。
浅拷贝:
浅拷贝得到的对象是重新创建的新对象,但浅拷贝只复制了对象的一层属性。所以改变浅拷贝后对象的基本类型值,原对象的基本类型值不会被改变;改变浅拷贝后对象的引用类型值,原对象的基本类型值就会被改变。
Object.assign()
:用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。var obj2 = {} Object.assign(obj2, obj) obj2.name = 'Mary' obj2.hobby[1] = '买' console.log(obj)
- 展开运算符:
var obj2 = {...obj} obj2.name = 'Mary' obj2.hobby[1] = '买' console.log(obj)
- 数组的
contact()
、slice()
方法都能执行浅拷贝,因为都会返回一个新数组。
改变 obj2 的 name 属性和 hobby 属性的第一个元素,可以看到 obj 的 name 属性值没有被改变,hobby 属性的第一个元素值被改变。
深拷贝:
深拷贝得到的对象是重新创建的新对象。深拷贝会递归复制所有层级,会对对象以及对象的所有子对象进行拷贝。所以改变赋值后对象的基本类型值和引用类型值,原对象的基本类型值和引用类型值都不会被改变。
深拷贝会带来性能上的问题。
-
通过 jQuery 中的
$.extend()
方法:用于将一个或多个对象的内容合并到目标对象。$.extend( deep, target, object1,…objectN );
参数:- deep:是否深度合并对象,默认为 false。第一个参数不支持传递 false。
- target:目标对象,其他对象的成员属性将被附加到该对象上。
- object1:被合并的对象。
var obj3 = {} $.extend(true, obj3, obj) obj3.name = 'Mary' obj3.hobby[1] = '买' console.log(obj)
-
通过 JSON:利用
JSON.stringify()
将 JS 对象序列化成 JSON 字符串,再使用JSON.parse()
来反序列化还原 JS 对象。var obj3 = JSON.parse(JSON.stringify(obj)) obj3.name = 'Mary' obj3.hobby[1] = '买' console.log(obj)
JSON.parse(JSON.stringify())
的缺陷:- 如果对象中有 undefined、函数和 Symbol,那么
JSON.parse(JSON.stringify())
后,undefined、函数和 Symbol 将丢失。 - 如果对象中有 NaN、Infinity 和 -Infinity,那么
JSON.parse(JSON.stringify())
后都会变成 null。 - 如果对象中有时间对象,那么
JSON.parse(JSON.stringify())
后,时间对象将变成字符串的形式。 - 如果对象中有 RegExp、Error 对象,那么
JSON.parse(JSON.stringify())
后将只得到空对象。 - 如果存在循环引用,即对象中有个属性又指向对象自身,那么
JSON.parse(JSON.stringify())
将会报错。
const originObj = { name: 'Lee', age: 18, sex: undefined, func: function(){ return 'Hello' }, [Symbol()]: 'abc', max: Infinity, min: NaN, date: new Date(1536627600000), reg: new RegExp('\\w+'), error: new Error('错误'), } console.log(originObj) const targetObj = JSON.parse(JSON.stringify(originObj)) console.log(targetObj)
- 如果对象中有 undefined、函数和 Symbol,那么
-
递归实现深拷贝:
// 判断一个值是否是对象 function isObject(value) { const valueType = typeof value return value !== null && (valueType === 'object' || valueType === 'function') } // 定义深拷贝函数:没有考虑 Set、Map、Symbol、Date、RegExp、Error 等类型、没有考虑循环引用的问题 function deepCopy(originValue) { // 1. 如果是基本类型值,直接返回 if (!isObject(originValue)) { return originValue } // 2. 如果是引用类型值,判断具体的类型,创建一个具体的新对象 // 2.1 如果是函数类型,函数是用来执行的,不需要进行深拷贝 if (typeof originValue === 'function') { return originValue } // 2.2 如果是数组类型或者对象类型 let targetValue = Array.isArray(originValue) ? [] : {} // 2.2.1 遍历每一项,重复深拷贝操作。如果属性值是基本类型值,直接返回;如果属性值是引用类型值,创建一个新对象并遍历重复深拷贝操作 for (const key in originValue) { targetValue[key] = deepCopy(originValue[key]) } return targetValue }