vue开发黑科技--利用引用类型的值处理复杂数据的编辑
栏目: JavaScript · 发布时间: 6年前
内容简介:现在前端框架和之前的前端开发方式有一个重要的区别————基于数据驱动。我们不需要再去关注dom本身,而是将主要精力放在如何操作数据上面。实际开发中,可以抽象成既然全部在完数据, 数据类型、算法就跑不掉了。本片介绍一个基于引用类型的vue黑科技, 在使用vue开发的时候可以更加方便。
现在前端框架和之前的前端开发方式有一个重要的区别————基于数据驱动。我们不需要再去关注dom本身,而是将主要精力放在如何操作数据上面。实际开发中,可以抽象成
既然全部在完数据, 数据类型、算法就跑不掉了。
本片介绍一个基于引用类型的vue黑科技, 在使用vue开发的时候可以更加方便。
引用类型
首先, 抄一段别人的博客
1.JavaScript中的变量类型有哪些? (1)值类型:字符串(string)、数值(number)、布尔值(boolean)、none、undefined (2)引用类型:对象(Object)、数组(Array)、函数(Function) 2.值类型和引用类型的区别 (1)值类型:1、占用空间固定,保存在栈中(当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。) 2、保存与复制的是值本身 3、使用typeof检测数据的类型 4、基本类型数据是值类型 (2)引用类型: 1、占用空间不固定,保存在堆中(当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。) 2、保存与复制的是指向对象的一个指针 3、使用instanceof检测数据类型 4、使用new()方法构造出的对象是引用型 复制代码
基础知识就是这些了。 举个小栗子。
总之记住一句话, 值类型传值, 引用类型传址
vue中的数据传递
在vue中的数据传递过程中, 是不涉及深拷贝的。 是通过props、vuex、v-bind等方法传递的引用类型都是传递的内存指针 在来个小栗子
<template> <div class="content"> <ul> <li v-for="(item, index) in list" :key="index" > <span @click="changeItemValue(item)">{{item.title}}</span> <span @click="deleteItem(index, list)">删除</span> </li> <li @click="addItem(list)">添加item</li> </ul> </div> </template> <script> export default { name: 'index', data () { return { list: [ { title: 'index0', }, { title: 'index1' }, { title: 'index2' }, { title: 'index3' }, { title: 'index4' } ] } }, methods: { changeItemValue(item) { item.title = item.title += '--|' }, deleteItem(index, list) { list.splice(index, 1) }, addItem(list) { list.push({ title: 'index' + list.length }) } } } </script> <style lang="scss" scoped> ul { width: 500px; margin: 200px auto; li { width: 200px; height: 50px; line-height: 50px; border: 1px solid pink; span:nth-child(2){ margin-left: 10px; color:red; } } } </style> 复制代码
在上面的例子中, 我们都没有使用 this.list[index]
的方式来获取需要修改的对象, 实际上, 方法里面传入的item就是 this.list
里对应的item的引用
这样书写会比通过传入索引--> 通过索引在list寻找该对象--> 修改该对象要方便的多。 特别是在数据层级比较深的时候。通过索引来查找可能会出现
changeItemValue(itemAIndex, itemBIndex, itemCindex, itemDIndex, value) { this.list[itemAIndex].childList[itemBIndex].childList[itemCindex].childList[itemDIndex].title = value } 复制代码
这酸爽~
我们举一个引用的小场景
页面的列表中, 每一个item有一个开关, 需要在保存的时候取出全部全部选中的
<template> <div class="content"> <ul> <li v-for="(item, index) in list" :key="index" > <span>{{item.title}}</span> <span @click="changeItemValue(item)">{{item.isSelect ? '选中' : '未选中'}}</span> </li> <li @click="save">保存</li> </ul> </div> </template> <script> export default { name: 'index', data () { return { list: [ { title: 'index0', isSelect: false }, { title: 'index1', isSelect: false }, { title: 'index2', isSelect: false }, { title: 'index3', isSelect: false }, { title: 'index4', isSelect: false } ] } }, methods: { changeItemValue(item) { item.isSelect = !item.isSelect }, save() { const data = this.list.filter(_ => _.isSelect) console.log(data) } } } </script> 复制代码
这得益于vue的访问劫持方法, 在修改对象的时候, 可以直接触发对象的观察者, 触发数据的更新和各种watch、computed、UI。 而vue的数组类型则是由vue特殊处理过的,才能实现对push、splice等方法的更新,这部分可以翻翻vue源码。
接下来我们讲一讲通过props的方式向子组件传递的情况, 众所周知,vue是不允许在组件内修改通过props传入的值的。实际中呢:
如果传入的数据是值类型的, 那么不允许修改这个值 例如 this.string = '' 如果传入的数据是引用类型, 那么不允许修改这个数据的内存地址,反之呢,我们可以修改这个数据中的子数据 复制代码
感觉上这种操作是违反vue的单向数据流思想的, 但是实在是在开发中太好用了, 所以我只能说这是一种黑科技 来个例子, 我们修改一下上面的代码, 将li作为一个组件来管理一个对象
<template> <div class="content"> <ul> <Item v-for="(item, index) in list" :key="index" :item="item" /> <li @click="save">保存</li> </ul> </div> </template> <script> import Item from './Item' export default { name: 'index', components: { Item }, data () { return { list: [ { title: 'index0', isSelect: false }, { title: 'index1', isSelect: false }, { title: 'index2', isSelect: false }, { title: 'index3', isSelect: false }, { title: 'index4', isSelect: false } ] } }, methods: { save() { const data = this.list.filter(_ => _.isSelect) console.log(data) } } } </script> 复制代码
<template> <li> <span>{{item.title}}</span> <span @click="changeItemValue">{{item.isSelect ? '选中' : '未选中'}}</span> </li> </template> <script> export default { name: 'Item', props: ['item'], methods: { changeItemValue() { this.item.isSelect = !this.item.isSelect // 注意 如上面所说 在这里直接修改item就会报错, 反之 只修改item下面的值并不会 } } } </script> 复制代码
运行起来, 和之前并没有差异, 实际上props传进去的也是这个对象的引用, 修改的时候父组件的值也被同步修改了。这样我们可以在子组件里面修改对应的值, 而不需要$emit到父组件去修改。在处理复杂数据的时候, 可以减少很多负担 基于这种模式, 我们在处理一个复杂数据的编辑的时候, 就可以将每一块相对独立的子数据分别用组件去维护。 而且子组件的数据相对对立, 层级浅的时候, 我们还可以方便的使用computed计算属性来实现一些数据的校验,UI的处理。
在使用vuex的时候
在使用vudex做状态管理的时候, 情况和pros差不多。
如果绑定的的数据是值类型的, 那么不允许修改这个值 例如 this.string = '' 如果绑定的的数据是引用类型, 那么不允许修改这个数据的内存地址,反之呢,我们可以修改这个数据中的子数据 复制代码
但是有一点, 在使用vue-devtools工具的中会有点差异,简单来说通过这种方式修改了state中的值,在vue-devtools工具的vuex部分是不会更新的, 但是实际上数据是已经改变了。。 依旧是先前的那个例子, 我们将数据源从data改为vuex
computed: { list() { return this.$store.state.list } } 复制代码
我们通过这种方式改变值之后,
在组建视图, 我们能看到组建内的isSelect值已经更新了,
父组件的计算属性中 第一个对象的值也更新了
但是在vuex视图中 这个值没有被更新, 打印出来的值也是更新了的。。 如果有强迫症的话, 可以手动更新一下
mutations: { changeList(state, list) { state.list = list } }, this.$store.commit('changeList', this.$store.state.list) 复制代码
应用
基于这种方法, 我们在处理复杂数据的时候, 可以将相对独立的数据块分割出来用一个单独的vue组件来维护和修改。最后的修改结果都可以在原有的数据树中体现,在提交的时候对这个跟数据进行处理就好。而不用每一次修改都emit到父组件中处理。
注意事项
- 基于这种值引用的形式, 在子组件修改相应值的时候, 初始值其实已经被污染了, 所以有需要的话要做数据的深拷贝
- 在处理数组的时候, vue底层对响应的数组操作都有特殊处理过, 所以只要不直接修改数组的引用地址, 都可以触发数据的更新, 但是不能使用tihs.list = this.list.map(cb)类似的方法, 因为他们都会返回一个新的数组
- 计算属性和vuex的getter返回的值不能这样处理, 准确的说, 这两个值本身就不能修改, 但是通过计算属性返回vuex的值例外
- 在直接修改对象子值的时候, watch会有异常, 无法正确的获得oldVal的值。
- 在react中也可以类似的实现, 但是react不是基于数据访问劫持的, 所以修改之后还要手动state一次, 微信小程序同理
- 在微信小程序中, 写在模板中的函数是不能传参的,通过data写在dom上的值不能这么操作, 组建传入的值也是相当于深拷贝的, 不能这么玩了
如上图, 计算属性的值正常更新了, 通过deep watch的值, 两个都是新的值, 无法取得oldVal, 而不用deep的时候, 这个watch根本不会触发。
写在最后
通过这种方式, 在处理比较复杂的数据的时候有奇效, 但是隐隐约约还是有些怪异,表面稳如老狗,实际慌得不行。 也请大佬解惑
- 这样处理是不是违反了单向数据流的思想
- 会不会有其他的未知的隐患
最后感谢教给我这个方法的大佬@登峰
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Java 如何有效地避免OOM:善于利用软引用和弱引用
- 强引用、软引用、弱引用、虚引用
- java的强引用、软引用、弱引用、幻象引用,引用队列总结
- Java 对象引用方式 —— 强引用、软引用、弱引用和虚引用
- 强引用、软引用、弱引用、幻象引用有什么区别?
- 你确定真的了解 Java 四种引用(强引用、弱引用、软引用、虚引用)了吗?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Machine Learning in Action
Peter Harrington / Manning Publications / 2012-4-19 / GBP 29.99
It's been said that data is the new "dirt"—the raw material from which and on which you build the structures of the modern world. And like dirt, data can seem like a limitless, undifferentiated mass. ......一起来看看 《Machine Learning in Action》 这本书的介绍吧!