位置: IT常识 - 正文
推荐整理分享Vue2响应式原理(vue2响应式原理面试回答),希望有所帮助,仅作参考,欢迎阅读内容。
文章相关热门搜索词:vue2响应式原理循环便利源码,vue2响应式原理和vue3的区别,vue2响应式原理循环便利源码,vue2响应式原理源码,vue2响应式原理代码实现,vue2响应式原理和vue3的区别,vue2响应式原理缺点,vue2响应式原理缺点,内容如对您有帮助,希望把文章链接给更多的朋友!
vue的特性:数据驱动视图和双向数据绑定。vue官方文档也提供了响应式原理的解释:
深入响应式原理
Object.defineProperty()Object.defineProperty()的作用是直接在一个对象上定义一个新属性,或者修改一个属性
使用方式:Object.defineProperty(对象名,属性名,配置项)
<script>let person = {name: '张三',sex: '男',}Object.defineProperty(person,'age',{value: 18}) //不能参与遍历</script>上述写法是给person对象添加一个age属性,属性的值是18
但是这种写法:
不能进行枚举,即无法在遍历的时候获取到age属性的值不能被修改不能删除所以Object.defineProperty()还有其他配置项
Object.defineProperty(person,'age',{ value: 18 enumerable: true //控制属性是否可以枚举,get="_blank">默认值是false writeable: true //控制属性是否可以被修改,默认值是false configurable: true //控制属性是否可以被删除,默认值是false})现在有一个需求:定义一个新的变量number,当number的值修改后,person中age的值也相应被修改;而person中age的值被修改后,number的值也相应被修改。
这个时候需要借助新的配置项get和set
<script>let number = 18let person = {name: '张三',sex: '男',}//能够实现number的值修改后,person中age的值也相应被修改 Object.defineProperty(person,'age',{ //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值 get:function(){ return number }, //当有人修改person的age属性时,set函数(setter)就会被调用,且接收到修改的具体值 set(value){ number = value } })</script>数据代理数据代理就是通过一个对象代理另一个对象中属性的操作
vue就是通过vm对象来代理data对象中属性的操作
<body> <div id="app"> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> </div></body><script> const vm = new Vue({ el: '#app', data: { name: '张三', age: 18 } })</script>控制台输出vm,我们可以看到name和age这两个属性
这两个属性都是通过Object.defineProperty()添加到vm上,所以可以发现他们都有对应的getter/setter
也就是说:当读取vm中的name时,会调用getter,把data.name给name;当修改vm中的name时,会调用setter,修改data.name中的值(这里跟第一个例子是同一个道理)
但是我们会发现vm上没有data(疑惑:明明在创建vue实例对象的时候,设置了data,为什么取不到)
其实我们以为的这个data其实是_data,可以验证一下:
let data = { name: '张三', age: 18}const vm = new Vue({ el: '#app', data})控制台进行一下判断:
所以我们获取数据的时候,也可以通过vm._data.age来获取
vue为了编码更方便,进行了数据代理,遍历data中的所有属性,把每个属性都添加到vm中,指定getter/setter。
所以可以直接通过vm.age来获取数据
基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上为每一个添加vm上的属性,都指定一个getter/setter在getter/setter内部去操作(读/写)data中对应的属性实现双向绑定双向绑定就是数据发生变化时,视图也跟着变。核心是数据劫持和发布者-订阅者模式
数据劫持实质就是使用defineProperty重写getter/setter。当数据改变时,set就会劫持这个数据的变化,更新视图(view)
但是由于defineProperty无法检测到对象和数组内部的变化,所以遇到属性为对象时,会递归观察该属性;遇到数组时,会重写push、pop、shift等方法。
监测对象中的数据最开始会想认为利用getter/setter,但是这样会造成死循环。只要有人获取name的值,就会调用get,然后又会获取一次person.name,造成死循环。set同理。
//错误的代码!!!!!!!!!let person = { name: '张三',}Object.defineProperty(person, 'name', { get: function() { return person.name }, set(value) { person.age = name }})正确的做法是:监听数据的每一个属性,当监听到属性值发生变化时,通知订阅者去更新视图,重新进行模板解析。
<script> let data = { name: '张三', } //创建一个观察者实例对象,用于监视data中属性的变化 const obs = new Observer(data) //准备一个vm实例对象 let vm = {} vm._data = data = obs function Observer(obj) { //汇总对象中所有的属性形成一个数组 const keys = Object.keys(obj) //遍历 keys.forEach((k) => { Object.defineProperty(this, k, { get() { return obj[k] }, set(val) { obj[k] = val } }) }) }</script>上述代码只是一个例子,只会对一层对象进行处理,vue的操作是递归,直到数据类型是简单数据类型。
如需给后添加的属性做响应式,可以使用
Vue.set(object,propertyName,value)或vm.$set(object,propertyName,value)data: {student:{name: '张三',age: 18,friends:[{name:'小明',age:20},{name:'李四',age:15}]}}Vue.set(this.student, 'sex', '男')this.$set(this.student, 'sex', '男')监测数组中的数据这里可以去看一下vue的官方文档:
通过包裹数组更新元素的方法实现,本质就是做了两件事
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
所以在vue修改数组中的某个元素一定要用如下方法:
使用API:push(),pop(),shift(),splice(),sort(),reverse()等Vue.set(),vm.$set()上一篇:Dedecms标签Tag长度使用Titlelen属性控制(aspcms标签)
友情链接: 武汉网站建设