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. 看毛片就能AC算法

    KMP && ACA KMP: 吼哇! 反正网上教程满天飞,我就不写了. 发个自己写的模板 /** freopen("in.in", "r", ...

  2. c/c++学习系列之memset()函数

    [转载] memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的: 包含在<string.h>头文件中,可以用它对一片内存空间逐字节进行初始化: 原型为 : void *mems ...

  3. qt: 获取sql数据表的所有的字段;

    1. mysql 数据库: 转载: https://www.cnblogs.com/fuqia/p/8994080.html mysql安装成功后可以看到已经存在mysql.information_s ...

  4. pandas常用函数之shift

    shift函数是对数据进行移动的操作,假如现在有一个DataFrame数据df,如下所示: index value1 A 0 B 1 C 2 D 3 那么如果执行以下代码: df.shift() 就会 ...

  5. 包管理工具之Pipenv

    pipenv 都包含什么? pipenv 是 Pipfile 主要倡导者.requests 作者 Kenneth Reitz 写的一个命令行工具,主要包含了Pipfile.pip.click.requ ...

  6. SQL Server数据库的备份和还

    转:http://blog.csdn.net/zwj7612356/article/details/8188025 在sql server数据库中,备份和还原都只能在服务器上进行,备份的数据文件在服务 ...

  7. RubyMine 2017.3.2破解教程

    下载地址:http://www.3322.cc/soft/35519.html RubyMine 2017.3.2破解版是一款专为Ruby和Rails开发者准备的IDE(被誉为最智能的Ruby和Rai ...

  8. 第四节:框架前期准备篇之进程外Session的两种配置方式

    一. 基本介绍 1. 背景:Asp.Net默认的Session机制是进程内,存储在服务器端内存中,有这么几个缺点: ①:既然存在内存中,空间有限,不能存储大数据量信息,数据量多的话Session会被挤 ...

  9. windows7 java环境配置

    最近在工作碰到了在ie浏览器调用java程序时,出现了一些问题,所以在这里整理一下: jdk的下载地址为:http://666dx.pc6.com/wwb3/jdkx6417.zip 正对于windo ...

  10. Python3:关于列表的操作(合并、拼接,嵌套排序··)

    一:# 将2个列表合并成字典,按最少个数key=['winnie','anna','lisa']value=[18,20,22] k_v=dict(zip(key,value))print(k_v) ...