-
vue对象深拷贝_Vue 对数据对象实现深拷贝赋值
2020-12-20 19:06:27在日常的Vue开发工作中,我们经常对请求来的数据进行变量赋值操作,再用变量去进行数据渲染。 然而我们知道,我们经常用的赋值方式 “=” 实际上属于数据的浅拷贝,也就是当你改变赋值变量时,原数据也会发生相应...在日常的Vue开发工作中,我们经常对请求来的数据进行变量赋值操作,再用变量去进行数据渲染。 然而我们知道,我们经常用的赋值方式 “=” 实际上属于数据的浅拷贝,也就是当你改变赋值变量时,原数据也会发生相应变化。var a = ['1', '2', '3', '4', '5'];
var b = a;
b[0] = '2';
console.log(a); // ['2', '2', '3', '4', '5']
console.log(b); // ['2', '2', '3', '4', '5']
//因为b浅拷贝a, ab指向同一个内存地址(堆内存中存的值)
那当我们需要改变变量的值但是不改变原来数据的时候,我们可以借助JSON方法来实现数据的深拷贝赋值:JSON.parse(JSON.stringify(this.responseData));
e.g:let data1 = this.selectform.keyList
let data2 = JSON.parse(JSON.stringify(this.selectform.keyList))
data1.a = 'test'
console.log(data1.a) // test
console.log(this.selectform.keyList.a) // test
data2.a = 'test222'
console.log(keydata2.a) // test222
console.log(this.selectform.keyList.a) // test
*附深浅拷贝示意图:
浅拷贝:
深拷贝:
-
【Vue】深拷贝与浅拷贝的区别,实现深拷贝的几种方法
2018-12-07 18:02:11如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。 此篇文章中也会简单阐述到栈堆,基本...如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
此篇文章中也会简单阐述到栈堆,基本数据类型与引用数据类型,因为这些概念能更好的让你理解深拷贝与浅拷贝。
我们来举个浅拷贝例子:
let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b);
嗯?明明b复制了a,为啥修改数组a,数组b也跟着变了,这里我不禁陷入了沉思。
那么这里,就得引入基本数据类型与引用数据类型的概念了。
面试常问,基本数据类型有哪些,number,string,boolean,null,undefined五类。
引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等。
而这两类数据存储分别是这样的:
a.基本类型--名值存储在栈内存中,例如let a=1;
当你b=a复制时,栈内存会新开辟一个内存,例如这样:
所以当你此时修改a=2,对b并不会造成影响,因为此时的b已自食其力,翅膀硬了,不受a的影响了。当然,let a=1,b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。
b.引用数据类型--名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面浅拷贝的例子画个图:
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
1.我们怎么去实现深拷贝呢,这里可以递归递归去复制所有层级属性。
这么我们封装一个深拷贝的函数
function deepClone(obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; } let a=[1,2,3,4], b=deepClone(a); a[0]=2; console.log(a,b);
可以看到
跟之前想象的一样,现在b脱离了a的控制,不再受a影响了。 这里再次强调,深拷贝,是拷贝对象各个层级的属性,可以看个例子。JQ里有一个extend方法也可以拷贝对象,我们来看看
let a=[1,2,3,4], b=a.slice(); a[0]=2; console.log(a,b);
那是不是说slice方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把a改改
let a=[0,1,[2,3],4], b=a.slice(); a[0]=1; a[2][0]=1; console.log(a,b);
拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。
这里引用知乎问答里面的一张图
第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。
同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝,这里需要注意。
2.除了递归,我们还可以借用JSON对象的parse和stringify
function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone } let a=[0,1,[2,3],4], b=deepClone(a); a[0]=1; a[2][0]=1; console.log(a,b);
可以看到,这下b是完全不受a的影响了。
附带说下,JSON.stringify与JSON.parse除了实现深拷贝,还能结合localStorage实现对象数组存储。有兴趣可以阅读博客这篇文章。
localStorage存储数组,对象,localStorage,sessionStorage存储数组对象
3.除了上面两种方法之外,我们还可以借用JQ的extend方法。
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
let a=[0,1,[2,3],4], b=$.extend(true,[],a); a[0]=1; a[2][0]=1; console.log(a,b);
可以看到,效果与上面方法一样,只是需要依赖JQ库。
说了这么多,了解深拷贝也不仅仅是为了应付面试题,在实际开发中也是非常有用的。例如后台返回了一堆数据,你需要对这堆数据做操作,但多人开发情况下,你是没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题,深拷贝能帮你更安全安心的去操作数据,根据实际情况来使用深拷贝,大概就是这个意思。
-
vue对象深拷贝_JavaScript 中对象的深拷贝
2021-01-30 13:43:17对象的深拷贝与浅拷贝的区别如下:浅拷贝:仅仅复制对象的引用,而不是对象本身;深拷贝:把复制的对象所引用的全部对象都复制一遍。一. 浅拷贝的实现浅拷贝的实现方法比较简单,只要使用是简单的复制语句即可。1.1 ...对象的深拷贝与浅拷贝的区别如下:
浅拷贝:仅仅复制对象的引用,而不是对象本身;
深拷贝:把复制的对象所引用的全部对象都复制一遍。
一. 浅拷贝的实现
浅拷贝的实现方法比较简单,只要使用是简单的复制语句即可。
1.1 方法一:简单的复制语句 /* ================ 浅拷贝 ================ */
function simpleClone(initalObj) {
var obj = {};
for ( var i in initalObj) {
obj[i] = initalObj[i];
}
return obj;
}
客户端调用 /* ================ 客户端调用 ================ */
var obj = {
a: "hello",
b: {
a: "world",
b: 21
},
c: ["Bob", "Tom", "Jenny"],
d: function() {
alert("hello world");
}
}
var cloneObj = simpleClone(obj); // 对象拷贝
console.log(cloneObj.b); // {a: "world", b: 21}
console.log(cloneObj.c); // ["Bob", "Tom", "Jenny"]
console.log(cloneObj.d); // function() { alert("hello world"); }
// 修改拷贝后的对象
cloneObj.b.a = "changed";
cloneObj.c = [1, 2, 3];
cloneObj.d = function() { alert("changed"); };
console.log(obj.b); // {a: "changed", b: 21} // // 原对象所引用的对象被修改了
console.log(obj.c); // ["Bob", "Tom", "Jenny"] // 原对象所引用的对象未被修改
console.log(obj.d); // function() { alert("hello world"); } // 原对象所引用的函数未被修改
1.2 方法二:Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。 var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"
二. 深拷贝的实现
要实现深拷贝有很多办法,有最简单的 json.parse() 方法,也有常用的递归拷贝方法,和ES5中的 Object.create() 方法。
2.1 方法一:使用 JSON.parse() 方法
要实现深拷贝有很多办法,比如最简单的办法是使用 JSON.parse(): /* ================ 深拷贝 ================ */
function deepClone(initalObj) {
var obj = {};
try {
obj = JSON.parse(JSON.stringify(initalObj));
}
return obj;
} /* ================ 客户端调用 ================ */
var obj = {
a: {
a: "world",
b: 21
}
}
var cloneObj = deepClone(obj);
cloneObj.a.a = "changed";
console.log(obj.a.a); // "world"
这种方法简单易用。
但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
2.2 方法二:递归拷贝
代码如下: /* ================ 深拷贝 ================ */
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
if (typeof initalObj[i] === 'object') {
obj[i] = (initalObj[i].constructor === Array) ? [] : {};
arguments.callee(initalObj[i], obj[i]);
} else {
obj[i] = initalObj[i];
}
}
return obj;
}
上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
改进版代码如下: /* ================ 深拷贝 ================ */
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];
// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
2.3 方法三:使用Object.create()方法
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。 /* ================ 深拷贝 ================ */
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];
// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
三. 参考:jquery.extend()方法的实现
jQuery.js的jQuery.extend()也实现了对象的深拷贝。下面将官方代码贴出来,以供参考。
官方链接地址:https://github.com/jquery/jquery/blob/master/src/core.js。 jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = jQuery.isArray( copy ) ) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
这篇文章主要是介绍js关于深拷贝的内容,其它的内容可以查看聚米学院以前发表的文章
-
关于Vue的深拷贝数组问题
2020-12-02 11:16:48关于Vue的深拷贝问题 对于vue的赋值,当改变子元素的值时,会发现父级元素也被修改了,当然,如果就需要的是这种效果,那就没啥好说的,但是如果只想单纯的赋值,不改变原数据那就需要解决这个问题,对于vue的赋值,...关于Vue的深拷贝问题
对于vue的赋值,当改变子元素的值时,会发现父级元素也被修改了,当然,如果就需要的是这种效果,那就没啥好说的,但是如果只想单纯的赋值,不改变原数据那就需要解决这个问题,对于vue的赋值,赋的值其实是赋了原来数据的地址,所以才会出现这种情况,而我们想要的是值传递,而不是地址传递,可以借助json转化来实现
var obj={}; obj=JSON.parse(JSON.stringify(this.templateData));//this.templateData是父组件传递的对象
return obj在用json之前我用过{…row}的方式解决深拷贝问题,如果只赋值对象没有问题,但是如果涉及到的是数组,就会出现获取不到数组长度的现象,我也不知道为什么,所以转用了json
-
vue对象深拷贝_[PHP 技巧] 不要直接克隆对象,请使用深拷贝
2020-12-26 15:01:13其背后的原理在于默认创建一个与原有对象的属性值完全一样的新对象,此外,也可以通过类的 __clone() 方法来实现自定义行为。虽然该描述与我们的期望相符,但是,如果克隆的对象里面包含了对象类型的属性,可能会... -
vue 拷贝 数组_Vue实现对数组、对象的深拷贝、复制
2020-12-20 10:52:55深拷贝:复制对象方法一JSON.parse(JSON.stringify())示例:computed: {data: function () {var obj={};obj=JSON.parse(JSON.stringify(this.templateData)); //this.templateData是父组件传递的对象return obj}}... -
vue对象深拷贝_[PHP 技巧] 不要直接克隆对象,请使用深拷贝(life)
2020-12-26 15:01:12其背后的原理在于默认创建一个与原有对象的属性值完全一样的新对象,此外,也可以通过类的 __clone() 方法来实现自定义行为。虽然该描述与我们的期望相符,但是,如果克隆的对象里面包含了对象类型的属性,可能会... -
vue 使用lodash实现对象数组深拷贝操作
2020-10-14 19:15:52主要介绍了vue 使用lodash实现对象数组深拷贝操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 -
vue 拷贝 数组_vue 使用lodash实现对象数组深拷贝操作
2021-01-12 12:42:04补充知识:vue iview上传多文件只发送一次ajax请求,并根据上传进度显示上传进度条 前言 基于iview的上传组件(Upload)以及进度条组件(Progress) 思路 使用Upload组件提供的上传文件之前的钩子,将所有上传文件拦截... -
vue 对象数组深拷贝
2020-07-21 09:19:29实现对象深拷贝 // 定义一个深拷贝函数 接收目标target参数 deepClone(target) { // 定义一个变量 let result; // 如果当前需要深拷贝的是一个对象的话 if (typeof target === "object") { // 如果是一个... -
vue传递数组对象_Vue实现对数组、对象的深拷贝、复制
2020-12-19 06:59:10前言我在使用vue进行前端开发的时候,wnm, 出现了在java中开发的时候遇到的问题,对象引用, 我把A数组赋值给B数组后,我B数组push了一个new value, 导致A数组中也多了一个value,一下子我就想到了对象的引用了,... -
Vue实现对数组、对象的深拷贝、复制
2019-10-09 04:31:00当组件间传递对象时,由于此对象的引用类型指向的都是一个地址(除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝),如下 数组: var a = [1,2,3]; var b = a; b.push(4); ... -
vue 使用lodash实现对象数组深拷贝
2019-11-12 17:57:40<template> <div></div> </template> <script> export default { mounted() { this.init(); }, methods: { init() { let _ = require('lodash');... let o...
-
MHA 高可用 MySQL 架构与 Altas 读写分离
-
2.2: 磁盘空间管理 、 交换空间.docx
-
机器学习中的概率论知识
-
安卓开发api!闭关在家37天“吃透”这份345页PDF,深度解析,值得收藏
-
r9 5900h参数 r9 5900h核显性能
-
day03
-
实现 MySQL 读写分离的利器 mysql-proxy
-
TPS5430 DCDC转+5V-5V双电源AD设计硬件原理图+PCB+3D封装库文件.zip
-
VMware vSphere ESXi 7 精讲/VCSA/VSAN
-
Python Qt 简介
-
access应用的3个开发实例
-
H3C S5560-SI系列交换机彩页_v2.pdf
-
C/C++:马踏棋盘问题(非递归)(含完整注释).rar
-
PowerBI重要外部工具详解
-
R9 5900H 和R9 4900H 的差别大吗
-
华为1+X——网络系统建设与运维(中级)
-
GUI编程Pyqt5之操作SQLite代码碎片
-
《python数据分析与数据化运营》4.rar
-
【拯救者 】数据库系统概论速成
-
基于STM32的步进电机控制系统.pdf