本文章转载:https://www.yht7.com/news/116487

1.问题描述

父组件传值给子组件,子组件改变传过来的值后,父组件的值也会跟着改变。
这个问题比较冷门,平时如果对组件通信使用得比较简单,一般不会遇到。

2.原因剖析

核心:双向绑定
父子组件传值的时候涉及双向绑定,当传值为 object 类型时,传值之后数据源会被改变。

深拷贝与浅拷贝
下文详细讲。

3.解决方案

我目前采用的解决办法是:
传值的时候不要直接传数据源,而是通过拷贝或者定义新变量等方式传值。
简单处理就 JSON.parse(JSON.stringify(obj)),但是这种简单粗暴的方法有其局限性。当值为 undefined、function、symbol 会在转换过程中被忽略。所以,对象值有这三种的话用这种方法会导致属性丢失。
剩下的就是自写深拷贝的工具函数,或者直接借助第三方的库函数,下面展开讲。

4.深拷贝和浅拷贝

JavaScript中的浅拷贝与深拷贝,只是针对复杂数据类型(Object,Array)的复制问题。浅拷贝与深拷贝都可以实现在已有对象上再生出一份的作用。但是对象的实例是存储在堆内存中然后通过一个引用值去操作对象,由此拷贝的时候就存在两种情况了:拷贝引用和拷贝实例,这也是浅拷贝和深拷贝的区别。
下图为JavaScript复杂数据类型的浅拷贝示意图:

浅拷贝

浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响。

值得注意的是:Object.assgin() 是浅拷贝,它只能深拷贝第一层,深层的还是浅拷贝。因为 Object.assign() 拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。(摘选自MDN)

MDN讲述 assign 的时候,就有一个典型的例子,这里是文章链接。

下面列举第一类浅拷贝 - 拷贝原对象的引用:

/*** 对象的浅拷贝*/
var obj1 = {name:"wenyuan",age: 22
}
var obj2 = obj1;
obj2["job"] = "coder";
console.log(obj1); //Object {name: "wenyuan", age: 22, job: "coder"}
console.log(obj2); //Object {name: "wenyuan", age: 0, job: "coder"}/* ------------------------- 华丽的分割线 ------------------------- *//*** 数组的浅拷贝*/
var arr1 = [1, 2, 3, "4"];
var arr2 = arr1;
arr2[1] = "test";
console.log(arr1); // [1, "test", 3, "4"]
console.log(arr2); // [1, "test", 3, "4"]

接下来看第二类浅拷贝 - 源对象拷贝实例,其属性对象拷贝引用:
这种情况,外层源对象是拷贝实例,如果其属性元素为复杂数据类型(Object、Array)时,内层元素拷贝引用。
对源对象直接操作,不影响另外一个对象,但是对其属性操作时候,会改变另外一个对象的属性的值。

/*** 对象的浅拷贝* jQuery的 $.extend(a,b) 或 $.extend({},a,b)*/
var obj1 = {name:"wenyuan",age: 22,social: {blog: "www.wenyuanblog.com"},skills: ["js", "html", "css", "python"]
}
var obj2 = $.extend({},obj1);
console.log(obj1 === obj2) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.social === obj2.social) // 输出true,说明对于Object类型的属性是拷贝引用
console.log(obj1.skills === obj2.skills) // 输出true,说明对于Array类型的属性是拷贝引用/*** 对象的浅拷贝* ES6的 Object.assign() 和 对象扩展运算符...*/
var obj1 = {name:"wenyuan",age: 22,social: {blog: "www.wenyuanblog.com"},skills: ["js", "html", "css", "python"]
}
var obj2 = Object.assign({},obj1);
console.log(obj1 === obj2) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.social === obj2.social) // 输出true,说明对于Object类型的属性是拷贝引用
console.log(obj1.skills === obj2.skills) // 输出true,说明对于Array类型的属性是拷贝引用
var obj3 = {...obj1};
console.log(obj1 === obj3) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.skills === obj3.skills) // 输出true,说明对于Array类型的属性是拷贝引用
console.log(obj1.skills === obj3.skills) // 输出true,说明对于Array类型的属性是拷贝引用/* ------------------------- 华丽的分割线 ------------------------- *//*** 数组的浅拷贝* Array.prototype.slice()*/
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = arr1.slice(0);
console.log(arr1 === arr2); // 输出false,说明外层数组拷贝的是实例
console.log(arr1[0] === arr2[0]); // 输出true,说明其元素拷贝的是引用/*** 数组的浅拷贝* Array.prototype.concat()*/
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = arr1.concat();
console.log(arr1 === arr2); // 输出false,说明外层数组拷贝的是实例
console.log(arr1[0] === arr2[0]); // 输出true,说明其元素拷贝的是引用/*** 数组的浅拷贝* ES6的 Object.assign() 和 对象扩展运算符...* 由于数组是特殊的对象,所以ES6中的这种方式也可以用于数组*/
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = Object.assign([],arr1)
var arr3 = { ...arr1 };
console.log(arr1 === arr2); // 输出false,说明外层数组拷贝的是实例
console.log(arr1 === arr3); // 输出false,说明外层数组拷贝的是实例
console.log(arr1[0] === arr2[0]); // 输出true,说明其元素拷贝的是引用
console.log(arr1[0] === arr3[0]); // 输出true,说明其元素拷贝的是引用

深拷贝

在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。

下面列举一些深拷贝的例子:

/*** 对象的深拷贝* JSON.stringify()和JSON.parse()* 这种深拷贝最简单,但有其局限性,上文已经提到过了*/
var obj1 = {name:"wenyuan",age: 22,social: {blog: "www.wenyuanblog.com"},skills: ["js", "html", "css", "python"]
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1 === obj2) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.social === obj2.social) // 输出false,说明对于Object类型的属性也是拷贝实例
console.log(obj1.skills === obj2.skills) // 输出false,说明对于Array类型的属性也是拷贝实例/*** 对象的深拷贝* jQuery的 $.extend(true,a,b)*/
var obj1 = {name:"wenyuan",age: 22,social: {blog: "www.wenyuanblog.com"},skills: ["js", "html", "css", "python"]
}
var obj2 = $.extend(true,obj1);
console.log(obj1 === obj2) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.social === obj2.social) // 输出false,说明对于Object类型的属性也是拷贝实例
console.log(obj1.skills === obj2.skills) // 输出false,说明对于Array类型的属性也是拷贝实例/*** 对象的深拷贝* 也可以自己写一个函数实现,用递归+判断,注意别进入死循环就好* 这里不举例了,以前我整理过一篇常用工具类函数的博客,里面包含了深拷贝函数*//*** 对象的深拷贝* lodash的_.cloneDeep*/
var obj1 = {name:"wenyuan",age: 22,social: {blog: "www.wenyuanblog.com"},skills: ["js", "html", "css", "python"]
}
var obj2 = _.cloneDeep(obj1);
console.log(obj1 === obj2) // 输出false,说明外层数组拷贝的是实例
console.log(obj1.social === obj2.social) // 输出false,说明对于Object类型的属性也是拷贝实例
console.log(obj1.skills === obj2.skills) // 输出false,说明对于Array类型的属性也是拷贝实例

以上就是JavaScript中的浅拷贝与深拷贝的知识点,以代码的形式记录下来,方便回顾。

到此这篇关于Vue父子组件传值的一些坑的文章就介绍到这了,更多相关Vue父子组件传值内容请搜索云海天教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持云海天教程!

原文链接:https://www.wenyuanblog.com/blogs/vue-pit-child-component-value-changes-affect-the-parent-component-value.html
转载:https://www.yht7.com/news/116487

vue父子组件传值的一些坑(深浅拷贝)相关推荐

  1. vue父子组件传值:详解父组件向子组件传值(props)

    vue父子组件传值:父组件向子组件传值用的是props 1.定义父组件 1)父组件想要向子组件传值时,那么需要在子组件引入的地方绑定一个属性,属性值就是要传的数据,并且要在父组件中引入子组件. 2)这 ...

  2. vue父子组件传值之 $emit和props

    vue父子组件传值之 $emit和props 前言 子组件向父组件传值 父组件向子组件传值 前言 在进行vue的项目中,我们难免会需要父子组件之间进行传值,父子组件传值可以通过 $emit和props ...

  3. Vue父子组件传值----$emit子传父

    Vue父子组件传值是个比较经典的问题,在这里,咱们先谈一下,子组件给父组件传值. 这是一个子组件 <!-- 子组件1 --> <template><div class=& ...

  4. Vue父子组件传值问题

    今天在编写vue子组件时遇到的两个问题来分享以下 父子组件传值问题 父组件 <md-editor ref="mdEditor" :text="form.conten ...

  5. vue父子组件传值之异步之后子组件无法拿到父组件传的值

    在vue中父子组件传值是非常常见的,父组件给子组件传值使用的是props,子组件给父组件传值使用的是$emit 但是今天就不详细的介绍父子组件之间传值,在这里我们介绍的是子组件在异步请求回来的参数无法 ...

  6. vue 父子组件传值

    父子组件传值 最常用的方法(4种) 1 . 父组件 传递数据 给子组件(props)vue官方文档 特别注意!!特别注意!!特别注意!! props传值的类型如果是Object类型,如对象,数组等,传 ...

  7. 快速理解Vue父子组件传值

    组件化开发是目前前端开发必备的开发技能,组件化开发可以大大提高开发效率 今天整理一下Vue的父子组件传值方式,方便还没有理解的朋友学习. 1.父组件向子组件传值 <!-- 父组件 --> ...

  8. VUE父子组件传值(含实例)

    vue父子组件通信 这里的movies数组和message字符串,相当于是在父组件中对要传给子组件的数据做赋值或者计算等操作. 1.父传给子(在子组件中改数据) 父组件: 1.在子组件上绑定数据arr ...

  9. Vue父子组件传值.sync

    传统的父子组件之间传值,父组件通过 :变量="xxx"将值传给子组件,子组件通过props进行接收.但是子组件只有读的属性,不可以对数据进行更改,所以$emit传回父组件,由父组件 ...

最新文章

  1. 【Anychat音视频开发】apache防盗链之mod_perl
  2. poi jxl 生成EXCEL 报表
  3. Dubbo(十)之配置加载流程
  4. [转] 【领导必读】唐僧为什么可以领导孙悟空
  5. 前置++与后置++的要点分析
  6. HTTP请求报文格式
  7. 换服务器原网站数据会丢失吗,ecs服务器更换操作系统后原服务器数据还在吗?...
  8. python处理pdf的第三方库_Python使用到第三方库PyMuPDF图片与pdf相互转换
  9. 架构高并发方案_架构 - 抖音微博等短视频千万级高可用、高并发架构设计
  10. python(模块)xlwt
  11. Maven 高级玩法
  12. hive连续天数统计思路
  13. nas系统存储服务器,我的瞎折腾NAS之系统选择篇
  14. 儒猿秒杀季!微服务限流熔断技术源码剖析与架构设计
  15. 蒙特卡洛(Monte Carlo)法求定积分
  16. 陈关荣老师整理的复杂网络的…
  17. HashMap中的遍历有序性探究
  18. 小程序学习从入门到熟练教程
  19. 2020年《财富》中国500强排行榜数据爬取,看看都有哪些
  20. 自己轻松打印电子发票

热门文章

  1. c语言reentrant,Keil C51對C語言的關鍵詞擴展之十五: reentrant
  2. discuz 发帖和回复页面,提示问题
  3. html加密文档如何打开,如何打开docx文件 在弹出窗口中选择加密的文件
  4. hive-nvl 函数
  5. 赤峰市计算机考试成绩查询系统,赤峰高考成绩查询系统入口
  6. 亲子类APP开发有哪些基础功能
  7. mongodb 超详细的操作集锦
  8. 本周学习积累:关于服务器相关软件的使用
  9. python 角点检测_python 实现Harris角点检测算法
  10. 我找不到我的电子邮件从 Outlook 数据文件 (.pst) 导入后,收发功能正常