JS对象的拷贝
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对象的拷贝的更多相关文章
- 两行代码搞定js对象深浅拷贝
有一段时间没有更新博客了,忙于工作.2018年刚过去,今天来开启2018第一篇博文.好了,咱们步入正题. 先上代码 /** * 遍历对象 * 1.判断是不是原始值 * 2.判断是数组还是对象 * 3. ...
- 超实用的JavaScript代码段 Item8 -- js对象的(深)拷贝
js 对象 浅拷贝 和 深拷贝 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: var Chinese = { nation:'中国' } var Doctor ...
- JS有关引用对象的拷贝问题
JS中有关引用对象的拷贝问题 问题描述:在开发过程中,拷贝一个对象数组给另一个数组的时候,改变新数组中对象的属性值,原数组中的对象属性值也跟着改变了. 例如新定义一个数组arr1,里面有两个对象,然后 ...
- JS对象的引用,对象的拷贝
目录 一.场景 二.浅拷贝 三.深拷贝 一.场景 除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝 将一个对象赋值给另外一个对象. var a = [1,2,3]; ...
- JS对象复制
在JavaScript很多人复制一个对象的时候都是直接用"=",因为大家都觉得脚本语言是没有指针.引用.地址之类的,所以直接用"="就可以把一个对象复制给另外一 ...
- js 对象与函数的区别
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- JS 对象的深拷贝和浅拷贝
转载于原文:https://www.cnblogs.com/dabingqi/p/8502932.html 这篇文章是转载于上面的链接地址,觉得写的非常好,所以收藏了,感谢原创作者的分享. 浅拷贝和深 ...
- JS中深浅拷贝 函数封装代码
一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...
- JS组件系列——表格组件神器:bootstrap table 包含了js对象的定义和对象成员函数的定义
前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉及,罪过,罪过.今天补起来吧.上午博主由零开始自己从头到尾使用了一遍Bootstrap Table ,遇到不少 ...
随机推荐
- Linux设备树(四 中断)
四 中断 中断一般包括中断产生设备和中断处理设备.中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件.中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生 ...
- 降维【PCA & SVD】
PCA(principle component analysis)主成分分析 理论依据 最大方差理论 最小平方误差理论 一.最大方差理论(白面机器学习) 对一个矩阵进行降维,我们希望降维之后的每一维数 ...
- 集成学习—boosting和bagging
集成~bagging~权值~组合~抽样~样例~基本~并行 一.简介 集成学习通过构建并结合多个学习器来完成学习任务,常可获得比单一学习器显著优越的泛化性能 根据个体学习器的生成方式,目前的集成学习方法 ...
- kubernetes云平台管理实战:deployment通过标签管理pod(十)
一.kubectl run命令拓展 1.RC创建 [root@k8s-master ~]# kubectl run web --generator=run/v1 --image=10.0.128.0: ...
- Fiddler--QuickExec
QuickExec在Fiddler中提供了比较快捷的功能服务. 在QuickExec输入框中输入命令,能快速地得到想要的结果. 快捷键:打开Fiddler后,按“Alt+q”,可将光标定位到Quick ...
- EF CodeFirst系列(5)---FluentApi
FluentApi总结 1.FluentApi简介 EF中的FluentApi作用是通过配置领域类来覆盖默认的约定.在EF中,我们通过DbModelBuilder类来使用FluentApi,它的功能比 ...
- beanPostProcessor与beanFactoryPostProcessor
BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer BeanFactoryPostProcessor会在所有的bean配置载入之后执 ...
- 第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)
一. 基本介绍 回忆: 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候,发现where方法里的参数是Expression<Func<T,bool> ...
- SpringBoot系列:Pojo validation
JSR 303 规范了bean validation, Hibernate validator实现了JSR 303所有的规范, 同时也是最常用的validator 工具包. 使用 Hibernate ...
- springMVC中controller的几种返回类型
==网文1,还不错,感觉比较老旧springMVC中controller的几种返回类型 - CSDN博客http://blog.csdn.net/qq_16071145/article/details ...