飞道的博客

vue 中由浅拷贝引发问题的一些场景

447人阅读  评论(0)

在工作的过程中踩了很多的由浅拷贝导致的坑,今天总结在这里,希望对大家有所帮助

1. 组件中直接抛出一个引用类型变量

🌰举个例子 (ps: 以下代码为伪代码,主要展示逻辑用)

子组件(uploadImg)定义一个上传图片的组件

基础功能:a. 上传图片,上传成功后抛出change 事件。

                 b. 上传成功的图片平铺展示,并展示删除按钮。点击删除按钮,弹出二次确认框。点击确认则删除,点击取消则不删除。


  
  1. // uploadImg.vue
  2. // 上传图片组件——子组件
  3. <template>
  4. <upload @change="uploadSuccess"> </upload>
  5. <div>
  6. <div v-for="(item, fileIndex) in imgUrls" :key="fileIndex" class="file-content">
  7. <div class="file-item">
  8. <div @click="delFile(fileIndex)" class="file-close">
  9. <el-tooltip class="item" effect="dark" content="删除" placement="right-start">
  10. <el-icon class="el-icon-close"> </el-icon>
  11. </el-tooltip>
  12. </div>
  13. </div>
  14. </div>
  15. </div>
  16. </div>
  17. </template>
  18. <script>
  19. data( ){
  20. return {
  21. imgUrls: []
  22. }
  23. },
  24. methods: {
  25. // 上传成功
  26. uploadSuccess (files) {
  27. files. forEach( item => {
  28. this. imgUrls. push({
  29. ...item,
  30. fileName: item. fileName
  31. })
  32. })
  33. this.$emit( 'change', this. imgUrls)
  34. },
  35. // 删除文件
  36. delFile (fileIndex) {
  37. this.$confirm( '图片删除后不能恢复,确认删除?', '提示'). then( () => {
  38. this. imgUrls. splice(fileIndex, 1)
  39. })
  40. this.$emit( 'change', this. imgUrls)
  41. }
  42. }
  43. </script>

父组件使用方法1


  
  1. <template>
  2. <upload-img @change="change"> </upload-img>
  3. </template>
  4. <script>
  5. data( ){
  6. return {
  7. imageList
  8. }
  9. },
  10. methods: {
  11. change( list) {
  12. this. imageList = list
  13. console. log( this. imageList)
  14. }
  15. }
  16. </script>

我们使用以上方法,点击删除图片,确认删除。

获取到的 this.imageList,是删除成功之后的图片数组,无异常。删除和上传给父组件的值都是正确的。

父组件使用方法2


  
  1. <template>
  2. <upload-img @change="change"> </upload-img>
  3. </template>
  4. <script>
  5. data( ){
  6. return {
  7. imageList
  8. }
  9. },
  10. methods: {
  11. change( list) {
  12. this. imageList = list. map( item => item. url)
  13. console. log( this. imageList)
  14. }
  15. }
  16. </script>

我们使用以上方法,点击删除图片,确认删除。

获取到的 this.imageList,是删除之前的图片数组,有异常。

为啥会产生这样的异常呐??我们来分析一下

 由上图可见,抛出change事件的时机,和弹出二次确认弹窗的时间是异步的。

即:在弹出二次确认弹窗的时候,chang事件就已经触发了。反而在点击二次确认弹窗的确定按钮的时候并未触发chang事件。

那么问题来了,为啥第一种方式无异常咧?因为我们change事件抛出的是一个引用类型的数据,并且父组件对该值进行了浅拷贝。等子组件的imgUrls值更新之后,父组件的imageList的值也进行了更新。

第二种方式由异常的原因:第二种方法在赋值之前使用了一个map 的方法,map 会返回一个新数组,即进行了深拷贝

2. 直接将引用类型赋值给一个新的变量,对新变量进行处理

🌰举个例子

form表单中,输入一些数据,调用后端接口传参数是,需要对数据进行一些处理,比如金额,需要由元转成分

这时直接进行转化,就是导致页面上的展示数据,也会进行相应的变动。

常见于:数据长度变多或者变少,对象修改了某一个key 的值,却无变化。

常见的浅拷贝的方法?

1. Object.assign()

2. 解构赋值

3. ‘=’赋值

常见解决方法

1. 手写深拷贝递归复制

2. JSON做字符串转换

var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1))

该方法有副作用

        a. 它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

        b.RegExp对象是无法通过这种方式深拷贝

        c.function没办法转成JSON

        

3. 使用Object.create()方法

直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

附上创建对象的一些方法的差异:

附上创建对象的一些方法的差异:Object.create()、new Object()和{}的区别 - 掘金

4. 三方函数(常用)

如lodash


转载:https://blog.csdn.net/weixin_39975379/article/details/128715962
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场