vue data 值如何渲染_vue实现响应式原理即vue如何监听data的每个属性的变化

vue实现响应式原理即vue如何监听data的每个属性的变化★★★★

重要指数:★★★★

记住两点

1、使用 Object.defineProprety实现响应式原理 2、 data属性代理到vm(即是Vue实例)上

Object.defineProperty 是如何使用的?

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。因为 Object.defineProperty() 是ES6新增的一个方法,所有我们使用vue不支持IE低版本浏览器

 /*----------  defineProperty 基本使用  ------------*/
let obj = {}
let name = 'qdleader'

Object.defineProperty(obj, 'name', {
get: function () {
console.log('get')
return name
},
set: function (newValue) {
console.log('set')
name = newValue
}

})
console.log(obj.name)
obj.name = 'yyyang'
// 输出
// get
// qdleader
// set

defineProperty这个原理就是拦截对象,给对象的属性增加 set 和 get方法,因为核心是 defineProperty所以还需要对数组的方法进行拦截

对对象进行拦截
function observer(target){
// 如果不是对象数据类型直接返回即可
if(typeof target !== 'object'){
return target
}
// 重新定义key
for(let key in target){
defineReactive(target,key,target[key])
}
}
function update(){
console.log('update view')
}
function defineReactive(obj,key,value){
observer(value); // 有可能对象类型是多层,递归劫持
Object.defineProperty(obj,key,{
get(){
// 在get 方法中收集依赖
return value
},
set(newVal){
if(newVal !== value){
observer(value);
update(); // 在set方法中触发更新
}
}
})
}
const obj = {name:'qdleader'}
observer(obj);
obj.name = 'new-name';
输出:
update view


数组方法劫持
const oldProtoMehtods = Array.prototype
const proto = Object.create(oldProtoMehtods)
function update(){
console.log('update view')
}
function defineReactive(obj,key,value){
observer(value) // 有可能对象类型是多层,递归劫持
Object.defineProperty(obj,key,{
get(){
// 在get 方法中收集依赖
return value
},
set(newVal){
if(newVal !== value){
observer(value)
update() // 在set方法中触发更新
}
}
})
}
['push','pop','shift','unshift'].forEach(method=>{
Object.defineProperty(proto, method,{
get(){
update()
return oldProtoMehtods[method]
}
})
})
function observer(target){
if(typeof target !== 'object'){
return target
}
// 如果不是对象数据类型直接返回即可
if(Array.isArray(target)){
Object.setPrototypeOf(target, proto)
// 给数组中的每一项进行observr
for(let i = 0 ; i < target.length; i++){
observer(target[i])
}
return
}
// 重新定义key
for(let key in target){
defineReactive(target, key, target[key])
}
}
let obj = {hobby:[{name:'zhuanzhuan'}]}
observer(obj)
// 使用['push','pop','shift','unshift'] 方法,更改数组会触发视图更新
obj.hobby.push('转转')
// 更改数组中的对象也会触发视图更新
obj.hobby[0].name = 'new-name'
console.log(obj.hobby)
输出:
update view
update view
[ { name: [Getter/Setter] }, 'qdleader' ]

Object.defineProperty缺点:

无法监听数组的变化

需要深度遍历,浪费内存

模拟实现Vue响应式

// 模拟实现Vue响应式
let vm = {} // 我们把这个看做是Vue的一个实例
// data看作是Vue实例的data属性
let data = {
price:100,
name:'qdleader'
}


let key, value

for (const key in data) {
if (data.hasOwnProperty(key)) {
(function(key){
Object.defineProperty(vm,key,{ // 将data属性代理到vm上
get:function(){
console.log('get',data[key]) // 监听
return data[key]
},
set:function(newValue){
console.log('set',newValue) // 监听
data[key] = newValue
}
})
})(key)

}
}


console.log(vm.name)

福利来啦 跨越山海去拥抱你,你的付出不会被辜负,前端路一起加油。扫码回复资料可以领10g前端资料,也可回复加群,加入交流群。

6a1ca1e0ef7a526f849d9d5d961c7826.png

另有github每日更新精选面试题欢迎star
https://github.com/qdleader/qdleader

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值