1:对数据进行备份的时候,如果这个数据是基本的数据类型,那么很好办,通过赋值实现复制即可。

赋值与浅拷贝的区别
var obj1 = {
'name' : 'zhangsan',
'age' : '18',
'language' : [1,[2,3],[4,5]],
}; var obj2 = obj1; //赋值得到的对象 var obj3 = shallowCopy(obj1); //通过浅拷贝得到的对象
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
} obj2.name = "lisi"; //影响obj1
obj3.age = "20"; //不影响obj1 obj2.language[1] = ["二","三"]; //影响obj1
obj3.language[2] = ["四","五"]; //影响obj1 console.log(obj1);
//obj1 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//}; console.log(obj2);
//obj2 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//}; console.log(obj3);
//obj3 = {
// 'name' : 'zhangsan',
// 'age' : '20',
// 'language' : [1,["二","三"],["四","五"]],
//}; 注释:这是因为浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。所以就会出现改变浅拷贝得到的 obj3 中的引用类型时,会使原始数据得到改变
深拷贝方法1:JSON.parse(JSON.stringify(obj))
let obj1 = {
name:'pan'
} let obj2 = JSON.parse(JSON.stringify(obj1)) obj2.name = 'rui'
console.log(obj1) //{name:pan} console.log(obj2) //{name:rui}
console.log(obj1 === obj2) //false
//缺点:对象必须遵从JSON的格式
let obj1 = {
a: '1',
b: '2',
c: function func() {}
} let obj4 = JSON.parse(JSON.stringify(obj1)) console.log(obj4) //{ a: '1', b: '2' } 好像漏了些什么
深拷贝方法2:Object.assign(target, …sources)
//Object.assign() 方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
// 复制
let c = Object.assign({}, { a: 'apple' });
console.log(c); // { a: 'apple' } //合并
let o = {}
let c = Object.assign(o, { a: 'apple' }, { b: 'banana' }, { c: 'cake' } )
console.log(c) // { a: 'apple', b: 'banana', c: 'cake' } //如果对象本身存在的属性会更新,不存在的属性会增加
let o = {
name:'pan'
}
let oo = {
name:'rui',
id:100
} let c = Object.assign(o, oo);
console.log(o); //{name:'rui',id:100}
console.log(oo);//{name:'rui',id:100}
console.log(c);//{name:'rui',id:100}
// 判断是否为对象
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
//测试用例需要的对象
let test = {
num: 0,
str: '',
boolean: true,
unf: undefined,
nul: null,
obj: {
name: '我是一个对象',
id: 1
},
arr: [0, 1, 2],
func: function() {
console.log('我是一个函数')
},
date: new Date(0),
reg: new RegExp('/我是一个正则/ig'),
err: new Error('我是一个错误')
}
深度拷贝方法3:迭代递归法 for...in
// 迭代递归法:深拷贝对象与数组
function deepClone(obj) {
if (!isObject(obj)) {
throw new Error('obj 不是一个对象!')
}
//判断传进来的是对象还是数组
let isArray = Array.isArray(obj)
let cloneObj = isArray ? [] : {}
//通过for...in来拷贝
for (let key in obj) {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
} return cloneObj
}
let result = deepClone(test) console.log(result) for (let key in result) {
if (isObject(result[key]))
console.log(`${key}相同吗? `, result[key] === test[key])
}
//我们发现,arr 和 obj 都深拷贝成功了,它们的内存引用已经不同了,但 func、date、reg 和 err 并没有复制成功,因为它们有特殊的构造函数。
深度拷贝方法4:迭代递归法 Reflect
// 代理法
function deepClone(obj) {
if (!isObject(obj)) {
throw new Error('obj 不是一个对象!')
} let isArray = Array.isArray(obj)
let cloneObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(cloneObj).forEach(key => {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
}) return cloneObj
} let result = deepClone(test) console.log(result) for (let key in result) {
if (isObject(result[key]))
console.log(`${key}相同吗? `, result[key] === test[key])
}
//结果其实和使用for...in相同。

2 lodash 中的深拷贝  https://github.com/lodash/lodash/blob/master/.internal/baseClone.js

  let result = _.cloneDeep(test)

  我们发现,arr、obj、date、reg深拷贝成功了,但 func 和 err 内存引用仍然不变 //这跟 lodash 中的 cloneableTags 有关

3lodash自定义拷贝对象

function customizer(value) {
if (_.isElement(value)) {
return value.cloneNode(true);
}
} var el = _.cloneDeepWith(document.body, customizer); console.log(el === document.body);
// => false
console.log(el.nodeName);
// => 'BODY'
console.log(el.childNodes.length);
// => 20

4小姐姐,在了解一下

  4.1:对象成环,当我们使用上述方法(for...in 与Reflect都会出现栈溢出的错误,但是lodash却可以)

    注意:因为 lodash 使用的是栈把对象存储起来了,如果有环对象,就会从栈里检测到,从而直接返回结果,悬崖勒马。这种算法思想来源于 HTML5 规范定义的结构化克隆算法,它同时也解释了为什么 lodash 不对 Error 和 Function 类型进行拷贝。

  4.2:键不是字符串而是 Symbol

    使用for...in拷贝的时候就会拷贝失败,因为 Symbol 是一种特殊的数据类型,它最大的特点便是独一无二,所以它的深拷贝就是浅拷贝

改造for...in
function deepClone(obj) {
if (!isObject(obj)) {
throw new Error('obj 不是一个对象!')
} let isArray = Array.isArray(obj)
let cloneObj = isArray ? [] : {}
let symKeys = Object.getOwnPropertySymbols(obj)
// console.log(symKey)
if (symKeys.length > 0) {
symKeys.forEach(symKey => {
cloneObj[symKey] = isObject(obj[symKey]) ? deepClone(obj[symKey]) : obj[symKey]
})
}
for (let key in obj) {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
} return cloneObj
}

    使用Reflect是可以的

  4.3 for...in会拷贝原型上面的属性,对于下面代码,只有for..in能够成功,而其他的方法都不能追踪到原型上面

let childTest = Object.create(test)
let result = deepClone(childTest)

    4.4 对象上的属性又分为可枚举属性和不可枚举属性,如何拷贝不可枚举的属性呢?

//定义对象
Object.defineProperties(test, {
'obj': {
writable: false,
enumerable: false,
configurable: false
},
'arr': {
get() {
console.log('调用了get')
return [1,2,3]
},
set(val) {
console.log('调用了set')
}
}
}) function deepClone(obj, hash = new WeakMap()) {
if (!isObject(obj)) {
return obj
}
// 查表,防止循环拷贝
if (hash.has(obj)) return hash.get(obj) let isArray = Array.isArray(obj)
// 初始化拷贝对象
let cloneObj = isArray ? [] : {}
// 哈希表设值
hash.set(obj, cloneObj)
// 获取源对象所有属性描述符
let allDesc = Object.getOwnPropertyDescriptors(obj)
// 获取源对象所有的 Symbol 类型键
let symKeys = Object.getOwnPropertySymbols(obj)
// 拷贝 Symbol 类型键对应的属性
if (symKeys.length > 0) {
symKeys.forEach(symKey => {
cloneObj[symKey] = isObject(obj[symKey]) ? deepClone(obj[symKey], hash) : obj[symKey]
})
} // 拷贝不可枚举属性,因为 allDesc 的 value 是浅拷贝,所以要放在前面
cloneObj = Object.create(
Object.getPrototypeOf(cloneObj),
allDesc
)
// 拷贝可枚举属性(包括原型链上的)
for (let key in obj) {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key], hash) : obj[key];
} return cloneObj
}

    总结:微笑中透露着贫穷

  

 

JS对象的拷贝的更多相关文章

  1. 两行代码搞定js对象深浅拷贝

    有一段时间没有更新博客了,忙于工作.2018年刚过去,今天来开启2018第一篇博文.好了,咱们步入正题. 先上代码 /** * 遍历对象 * 1.判断是不是原始值 * 2.判断是数组还是对象 * 3. ...

  2. 超实用的JavaScript代码段 Item8 -- js对象的(深)拷贝

    js 对象 浅拷贝 和 深拷贝 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: var Chinese = { nation:'中国' } var Doctor ...

  3. JS有关引用对象的拷贝问题

    JS中有关引用对象的拷贝问题 问题描述:在开发过程中,拷贝一个对象数组给另一个数组的时候,改变新数组中对象的属性值,原数组中的对象属性值也跟着改变了. 例如新定义一个数组arr1,里面有两个对象,然后 ...

  4. JS对象的引用,对象的拷贝

    目录 一.场景 二.浅拷贝 三.深拷贝 一.场景 除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝 将一个对象赋值给另外一个对象. var a = [1,2,3]; ...

  5. JS对象复制

    在JavaScript很多人复制一个对象的时候都是直接用"=",因为大家都觉得脚本语言是没有指针.引用.地址之类的,所以直接用"="就可以把一个对象复制给另外一 ...

  6. js 对象与函数的区别

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  7. JS 对象的深拷贝和浅拷贝

    转载于原文:https://www.cnblogs.com/dabingqi/p/8502932.html 这篇文章是转载于上面的链接地址,觉得写的非常好,所以收藏了,感谢原创作者的分享. 浅拷贝和深 ...

  8. JS中深浅拷贝 函数封装代码

    一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...

  9. JS组件系列——表格组件神器:bootstrap table 包含了js对象的定义和对象成员函数的定义

    前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉及,罪过,罪过.今天补起来吧.上午博主由零开始自己从头到尾使用了一遍Bootstrap Table ,遇到不少 ...

随机推荐

  1. html页面中引入自签名证书的js web资源出现net::ERR_CERT_AUTHORITY_INVALID

    其实是浏览器客户端对自签名的内容认为不安全引起的,临时方法可以再浏览器中先直接访问下那个自签名的https地址,然后再访问有引用的那个页面就可以了. 以下内容引用自https://www.morong ...

  2. iOS开发者知识普及,Swift 挑战 Objective-C,谁会笑到最后?

    前言: 目前全球共有超过 7 亿台 iPhone 处于活跃状态,全球约有2000万名 iOS 开发者,这造就了 iOS 作为全球第二大移动设备平台的状态. 虽然安卓系统的全球市场占有率超过 iOS 系 ...

  3. matlab里面如何保留小数特定位数

    [转载]Matlab取整函数有: fix, floor, ceil, round.取整函数在编程时有很大用处. 一.取整函数 1.向零取整(截尾取整) fix-向零取整(Round towards z ...

  4. DirectX11 With Windows SDK--20 硬件实例化与视锥体裁剪

    前言 这一章将了解如何在DirectX 11利用硬件实例化技术高效地绘制重复的物体,以及使用视锥体裁剪技术提前将位于视锥体外的物体进行排除. 在此之前需要额外了解的章节如下: 章节回顾 18 使用Di ...

  5. springBoot总结

    springBoot总结: ssm基本的依赖: <dependencies> <!--添加依赖thymeleaf 可以访问html页面--> <!--<depend ...

  6. 第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式 :

    背景: 默认情况下,Quartz.Net作业是持久化在内存中的,即 quartz.jobStore.type = "Quartz.Simpl.RAMJobStore, Quartz" ...

  7. UEditor调用上传图片、上传文件等模块

    来源:https://www.cnblogs.com/lhm166/articles/6079973.html 说到百度富文本编辑器ueditor(下面简称ue),我不得不给它一个大大的赞.我们在网站 ...

  8. yolo类检测算法解析——yolo v3

    每当听到有人问“如何入门计算机视觉”这个问题时,其实我内心是拒绝的,为什么呢?因为我们说的计算机视觉的发展史可谓很长了,它的分支很多,而且理论那是错综复杂交相辉映,就好像数学一样,如何学习数学?这问题 ...

  9. 设计模式六: 模板方法(Template Method)

    简介 模板方法属于行为型模式的一种. 实现层面上, 在抽象类中定义了算法或流程的骨架, 将其中易变的部分延迟到子类实现, 也就是允许它的子类实现其中的某些步骤. 模板方法适用于算法不变, 但算法中某些 ...

  10. vue父子组件之间互相获取data值&调用方法(非props)

    vue 子组件调用父组件方法&数据 vue有$parent这么一个属性,在子组件中就能拿到父组件的数据 this.$parent.xxx 就能调用父组件的方法 this.$parent.xxx ...