大家都知道,js的对象是引用类型,如果直接var obj2 = obj,obj2和obj是共享同一个对象实体的,这往往不是我们想要的结果。

官方并没有给出通用的对象克隆方法:

我们给出以下几种写法:

1.通用对象克隆:

function clone(obj, hash = new WeakMap()) {
// 解决循环引用
if (hash.has(obj)) {
return hash.get(obj)
}
let temp = null;
if (obj instanceof Array) {
// 特殊处理数组对象类型
temp = []
hash.set(obj, temp)
obj.forEach(item => {
temp.push(clone(item, hash));
})
} else if (obj instanceof RegExp) {
// 特殊处理正则对象类型
const { source, global, ignoreCase, multiline } = obj;
let flags = '';
if (global) flags += 'g';
if (ignoreCase) flags += 'i';
if (multiline) flags += 'm';
temp = new RegExp(source, flags);
} else if (obj instanceof Date) {
// 特殊处理时间对象类型
temp = new Date(obj.getTime());
} else if (typeof obj === 'object') {
// 处理普通对象类型
// 以obj的原型为原型,构造一个新对象
temp = Object.create(obj.__proto__);
hash.set(obj, temp)
} else {
temp = obj;
}
// 任何对象类型,都遍历递归自身的属性
if (typeof obj === 'object') {
for (let [key, val] of Object.entries(obj)) {
temp[key] = clone(val, hash);
}
}
return temp;
}

遇到数组对象类型、正则对象类型、时间对象类型、普通对象类型都需要有自己的特殊,最后他们都需要遍历递归他们自身的属性

原始类型(包括Symbol)纯复制就可以了

函数做的浅拷贝(因为如果拷贝函数,只能用eval这个危险的工具了,所以这里函数仅作浅克隆,lodash的cloneDeep对函数也是浅克隆处理)

推荐阅读:https://juejin.im/post/5b235b726fb9a00e8a3e4e88

ps:这里还有一些坑,无法克隆 Error 对象,无法克隆原型,无法克隆不可枚举的属性.... 不过这个深克隆已经可以覆盖百分之99的场景了!!

2.JSON对象序列化方法

深拷贝,但是有一大堆坑(推荐阅读:https://juejin.im/post/5abb55ee6fb9a028e33b7e0a):

基础的5个大坑:

1. 函数不能拷贝

2. Symbol不能拷贝

4. undefined不能拷贝

5. 正则拷贝后变成普通对象

6. 循环引用的对象会报错

7. 数组的属性丢失

8. 数组里面的undefined会变成null

9. 会抛弃对象的constructor

。。。。估计还有很多我没想到的

let a = { age: undefined, sex: Symbol('male'), jobs: function() {}, name: 'yck' } 
let b = JSON.parse(JSON.stringify(a)) console.log(b) // {name: "yck"}

正常使用:

var obj = {a:1,b:2}
var newObj = JSON.parse(JSON.stringify(obj));

3.dom元素的复制——cloneNode

let div = document.getElementById('box');
let box2 = div.cloneNode(true);

4.es6新方法——Object.assign

浅拷贝

var obj = {a:1,b:2}
var newObj = Object.assign({}, obj);

5. MessageChannel的方法

异步的深克隆,但是无法克隆function 、Symbol

let obj = {a: 1,b: 2}

let {port1, port2} = new MessageChannel();
port2.onmessage = ev => console.log(ev.data)
port2.postMessage(obj)

总结:日常使用还是推荐用lodash的cloneDeep

js对象克隆的更多相关文章

  1. js 对象克隆方法总结(不改变原对象)

    1.通用对象克隆: function clone(obj){ let temp = null; if(obj instanceof Array){ temp = obj.concat(); }else ...

  2. js对象克隆, 深复制.

    亲测有效: //对象克隆 function clone(obj) { // Handle the 3 simple types, and null or undefined if (null == o ...

  3. js对象克隆方法

    方法1: function clone(obj){ var o; switch(typeof obj){ case 'undefined': break; case 'string' : o = ob ...

  4. js对象的深度克隆

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

  5. js深度克隆对象

    js深度克隆对象 js深度克隆对象简单的记录一下,如下代码: var obj = { typeOf: function(obj) { const toString = Object.prototype ...

  6. js对象简单、深度克隆(复制)

    javascript的一切实例都是对象,只是对象之间稍有不同,分为原始类型和合成类型.原始类型对象指的是字符串(String).数值(Number).布尔值(Boolean),合成类型对象指的是数组( ...

  7. JS对象复制

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

  8. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  9. 原型模式和基于原型继承的js对象系统

    像同样基于原型编程的Io语言一样,javascript在原型继承方面,实现原理和Io非常类似,javascript也遵守这些原则 所有数据都是对象 要得到一个对象,不是通过实例化类,而是找到一个对象作 ...

随机推荐

  1. Linux内核分析— —扒开系统调用的三层皮(上)

    实验部分 根据系统调用表,选取一个系统调用.我选得是mkdir这个系统调用,其系统调用号为39,即0x27 由于mkdir函数的原型为int mkdir (const char *filename, ...

  2. <构建之法>8,9,10章的读后感

    第八章 这一章主要讲的是需求分析,主要介绍在客户需求五花八门的情况下,软件团队如何才能准确而全面地找到这些需求. 第九章 问题:我们现在怎样培养才能成为一名合格的PM呢? 第十章 问题:如果典型用户吴 ...

  3. NSLog debug时打印 release时不打印

    创建.h文件,添加以下代码 #ifdef  DEBUG #define NSLog(...)  NSLog(__VA_ARGS__) #else #define NSLog(...)  {} #end ...

  4. Docker(十九)-Docker监控容器资源的占用情况

    启动一个容器并限制资源 启动一个centos容器,限制其内存为1G ,可用cpu数为2 [root@localhost ~]# docker run --name os1 -it -m 1g --cp ...

  5. 在 Linux 虚拟机中手动安装或升级 VMware Tools

    对于 Linux 虚拟机,您可以使用命令行工具手动安装或升级 VMware Tools. 本次Linux 虚拟机为CentOS6.5 先决条件开启虚拟机.确认客户机操作系统正在运行.由于 VMware ...

  6. pandas设置值、更改值

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/24 15:03 # @Author : zhang chao # @Fi ...

  7. free命令详解

    free的命令详解   free命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区. 语法 free [选项] 选项 -b 以Byte为单位显示内存的使用情况 -k 以K ...

  8. 嵌入式启动jetty

    由于jetty8以上版本已经抛弃JDK1.6,公司统一开发JDK又一直不升级,所以我们使用jetty8 pom.xml <project xmlns="http://maven.apa ...

  9. Django-website 程序案例系列-5 模态对话框实现提交数据

    html代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  10. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...