前端笔试或者面试的时候,很喜欢问的一个问题就是对象的深度克隆,或者说是对象的深度复制。其实这个问题说容易很容易,但是要说全面也挺不易。

  要弄明白对象的克隆,首先要明白js中对象的组成。在js中一切实例皆是对象,具体分为原始类型和合成类型。原始类型对象指的是number、string、boolean等,合成类型对象指的是array、object以及function。

  又或许你刚听说“深度克隆"这个词,简单来说,就是说有个变量a,a的值是个对象(包括基本数据类型),现在你要创建一个变量b,使得它拥有跟a一样的方法和属性等等。但是a和b之间不能相互影响,即a的值的改变不影响b值的变化。

  直接赋值可好?


var a = 1;
var b = a;
a = 10;
console.log(b); // 1 var a = 'hello';
var b = a;
a = 'world';
console.log(b); // hello var a = true;
var b = a;
a = false;
console.log(b); // true

  实践证明某些JavaScript的原始数据类型,如果要克隆直接赋值即可。

  关于function的深度复制:查阅了一些资料,function的深度复制似乎和原始数据类型的深度复制一样。

var a = function() {console.log(1);};
var b = a;
a = function() {console.log(2);};
b(); // 1

  本来我也是这么认为的,思考后我觉得function和普通的对象一样,只是我们在平常应用中习惯了整体的重新赋值,导致它在深度复制中的表现和原始类型一致:

var a = function() {console.log(1);};
a.tmp = 10;
var b = a;
a.tmp = 20;
console.log(b.tmp); // 20

  于是乎对于function类型的深度克隆,直接赋值似乎并不应该是一种最好的方法(尽管实际应用中足矣)。那么如何克隆?

function cloneFunction(f){
var fStr = f.toString();
var tmpF = undefined;
eval('tmpF = ' + fStr);
// 静态属性
for(var p in f){
if(f.hasOwnProperty(p)){
tmpF[p] = f[p];
}
}
// 原型
tmpF.prototype = f.prototype; return tmpF;
}

其实这里是不太严谨,比如,如果函数下属性p还是对象,这种情况就需要递归copy,这里只是简单阐述情景;类似的还有number、string、boolean通过new出来的对象;也是一样的情景;

  但是合成类型对象array、object呢?

var a = [0, 1, 2, 3];
var b = a;
a.push(4);
console.log(b); // [0, 1, 2, 3, 4]

  显然与预期不符,为什么会这样?因为原始数据类型储存的是对象的实际数据,而对象类型存储的是对象的引用地址。上面的例子呢也就是说a和b对象引用了同一个地址,无论改变a还是改变b,其实根本操作是一样的,都是对那块空间地址中的值的改变。

  于是我们知道了,对于基本的对象来说,不能只能用=赋值,思索后写下如下代码:


function deepClone(obj) {
var o = obj instanceof Array ? [] : {};
for(var k in obj) {
if(obj.hasOwnProperty(key)){
o[k] = typeof obj[k] === Object ? deepClone(obj[k]) : obj[k];
}
}
o .prototype = obj.prototype;
return o;
} var a = [[1, 2, 3], [4, 5, 6, 7]];
var b = deepClone(a);
console.log(b);

另外一种简单实现:

// 深复制
let deepClone= (obj) => {
return JSON.parse(JSON.stringify(obj));
};

  似乎可以解决一般的对象(包括Array)的深度克隆了,或许这儿会有疑问,new String(..)这类的也是对象啊,可是这样写你克隆不了啊...但是楼主觉得深度克隆的考点不在这里,可能在于:

  1. 原始数据类型的直接赋值
  2. function的exception
  3. 对象的深度克隆中Array类型的判断
  4. 克隆函数的递归调用

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

  1. JS如何进行对象的深克隆(深拷贝)?

    JS中,一般的赋值传递的都是对象/数组的引用,并没有真正的深拷贝一个对象,如何进行对象的深拷贝呢? var a = {name : 'miay'}; var b = a; b.name = 'Jone ...

  2. JS对象继承篇

    JS对象继承篇 ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 原型链 其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法 function Person() ...

  3. JS 对象封装的常用方式

    JS是一门面向对象语言,其对象是用prototype属性来模拟的,下面,来看看如何封装JS对象. 常规封装 function Person (name,age,sex){ this.name = na ...

  4. JSON字符串和JS对象之间的转换

    JSON字符串和JS对象之间的转换 1 json字符串转换为js对象 1.1 标准json格式字符串转换为Js对象  JSON字符串 str JSON.parse(str) eval(str) eva ...

  5. js 对象的_proto_

    js 对象呢,有个属性叫_proto_,以前没听说过,也没关注,最近看这个原型,就被迫知道了这个东西,js 这里面的东西,真是规定的很奇怪,具体为啥也不知道,就测试发现的,对象的_proto_属性,和 ...

  6. js对象/数组深度复制

    今天碰到个问题,js对象.数组深度复制:之前有见过类似的,不过没有实现函数复制,今晚想了一下,实现代码如下: function clone(obj) { var a; if(obj instanceo ...

  7. js对象的深度克隆

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

  8. js对象详解

    js自定义对象 一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在J ...

  9. js对象常用2中构造方法

    //js 对象的构造方法通常有2中情况: //第一种是通过json对象构造 var persion={ name:"孙悟空", age:40, eat:function () { ...

随机推荐

  1. HTML网页设计基础笔记 • 【第4章 CSS3基础】

    全部章节   >>>> 本章目录 4.1 CSS 概述 4.1.1 CSS 简介 4.1.2 CSS3 基本语法 4.1.3 样式表的分类 4.2 CSS 基本选择器 4.2. ...

  2. Java面向对象笔记 • 【第11章 Swing高级应用】

    全部章节   >>>> 本章目录 11.1 JTable表格组件 11.1.1 JTable表格组件 11.1.2 实践练习 11.2 菜单组件 11.2.1 菜单组件 11. ...

  3. Struts2中通过Ajax传递json数据

    1.导入Struts2所需要的jar包 下载Struts2的jar包时,可以下载struts-2.5.13-min-lib.zip,然后放到项目的/WebContent/WEB-INF/lib路径下s ...

  4. MySQL启用SSL连接

    1.手动创建自认证证书 1.1 创建CA证书 openssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days 3600 ...

  5. CVE-2021-45232 Apache APISIX 从未授权访问到RCE

    00x1漏洞环境 Apache APISIX Dashboard 2.7 - 2.10 版本受到影响 通过git拉取在docker搭建环境 git clone https://github.com/a ...

  6. FastAPI快速查阅

    官方文档主要侧重点是循序渐进地学习FastAPI, 不利于有其他框架使用经验的人快速查阅 故本文与官方文档不一样, 并补充了一些官方文档没有的内容 安装 包括安装uvicorn $pip instal ...

  7. quasar框架在store中使用router跳转页面报错

    网上一通百度,终于在这篇博客中找到原因.  https://www.cnblogs.com/remly/p/12995936.html 原因是: 在router中导出了一个工厂函数, 既然是一个函数, ...

  8. 细谈 Java 匿名内部类 【分别 使用 接口 和 抽象类实现】

    1.前言 匿名内部类是什么东西? 没有名字的内部类就是匿名内部类. 什么场景使用? 匿名内部类适合创建那种只需要一次使用的类. 这是个很有用的东西,可想而知,如果不使用匿名内部类,哪些只需要使用一次的 ...

  9. 【Azure 应用服务】一个 App Service 同时部署运行两个及多个 Java 应用程序(Jar包)

    问题描述 如何在一个AppService下同时部署运行多个Java 应用程序呢? 问题解答 因为App Service的默认根目录为 wwwroot.如果需要运行多个Java 应用程序,需要在 www ...

  10. CentOS6.5下安装Hadoop-2.7.3(图解教程)

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6627365258090512909/ 已安装好虚拟机(3个节点) YUM源已安装好.系统版本CentOS6.5.j ...