Vue 核心之数据劫持

1.监听对象属性的变化

这个应该是Vue敲开数据绑定的前大门,它通过observe(观察)每个对象的属性,添加到订阅器dep中,当数据发生变化的时候发出一个notice(预告)。 相关源代码如下:(作者采用的是ES6+flow写的,代码在src/core/observer/index.js模块里面)。

export function defineReactive (

obj: Object,

key: string,

val: any,

customSetter?: Function

) {

const dep = new Dep()//创建订阅对象

const property = Object.getOwnPropertyDescriptor(obj, key)//获取obj对象的key属性的描述

//属性的描述特性里面如果configurable为false则属性的任何修改将无效

if (property && property.configurable === false) {

return

}

// cater for pre-defined getter/setters

const getter = property && property.get

const setter = property && property.set

let childOb = observe(val)//创建一个观察者对象

Object.defineProperty(obj, key, {

enumerable: true,//可枚举

configurable: true,//可修改

get: function reactiveGetter () {

const value = getter ? getter.call(obj) : val//先调用默认的get方法取值

//这里就劫持了get方法,也是作者一个巧妙设计,在创建watcher实例的时候,通过调用对象的get方法往订阅器dep上添加这个创建的watcher实例

if (Dep.target) {

dep.depend()

if (childOb) {

childOb.dep.depend()

}

if (Array.isArray(value)) {

dependArray(value)

}

}

return value//返回属性值

},

set: function reactiveSetter (newVal) {

const value = getter ? getter.call(obj) : val//先取旧值

if (newVal === value) {

return

}

//这个是用来判断生产环境的,可以无视

if (process.env.NODE_ENV !== ‘production’ && customSetter) {

customSetter()

}

if (setter) {

setter.call(obj, newVal)

} else {

val = newVal

}

childOb = observe(newVal)//继续监听新的属性值

dep.notify()//这个是真正劫持的目的,要对订阅者发通知了

}

})

}

以上是Vue监听对象属性的变化,那么问题来了,我们经常在传递数据的时候往往不是一个对象,很有可能是一个数组,那是不是就没有办法了呢,答案显然是否则的。那么下面就看看作者是如何监听数组的变化:

监听数组的变化

我们还看先看这段源码:

const arrayProto = Array.prototype//原生Array的原型

export const arrayMethods = Object.create(arrayProto)

;[

‘push’,

‘pop’,

‘shift’,

‘unshift’,

‘splice’,

‘sort’,

‘reverse’

]

.forEach(function (method) {

const original = arrayProto[method]//缓存元素数组原型

//这里重写了数组的几个原型方法

def(arrayMethods, method, function mutator () {

//这里备份一份参数应该是从性能方面的考虑

let i = arguments.length

const args = new Array(i)

while (i–) {

args[i] = arguments[i]

}

const result = original.apply(this, args)//原始方法求值

const ob = this.ob//这里this.__ob__指向的是数据的Observer

let inserted

switch (method) {

case ‘push’:

inserted = args

break

case ‘unshift’:

inserted = args

break

case ‘splice’:

inserted = args.slice(2)

break

}

if (inserted) ob.observeArray(inserted)

// notify change

ob.dep.notify()

return result

})

})

//定义属性

function def (obj, key, val, enumerable) {

Object.defineProperty(obj, key, {

value: val,

enumerable: !!enumerable,

writable: true,

configurable: true

});

}

上面的代码主要是继承了Array本身的原型方法,然后又做了劫持修改,可以发出通知。Vue在observer数据阶段会判断如果是数组的话,则修改数组的原型,这样的话,后面对数组的任何操作都可以在劫持的过程中控制。结合Vue的思想,我们简单的写个小demo方便更好的理解:

var arrayMethod = Object.create(Array.prototype);

[‘push’,‘shift’].forEach(function(method){

Object.defineProperty(arrayMethod,method,{

value:function(){

var i = arguments.length

var args = new Array(i)

while (i–) {

args[i] = arguments[i]

}

var original = Array.prototype[method];

var result = original.apply(this,args);

console.log(“已经控制了,哈哈”);

return result;

},

enumerable: true,

writable: true,

configurable: true

})

})

var bar = [1,2];

bar.proto = arrayMethod;

bar.push(3);//控制台会打印出 “已经控制了,哈哈”;并且bar里面已经成功的添加了成员 ‘3’

整个过程看起来好像没有什么问题,似乎Vue已经做到了完美,其实不然,Vue还是不能检测到数据项和数组长度改变的变化,例如下面的调用:

vm.items[index] = “xxx”;

vm.items.length = 100;

我们尽量避免这样的调用方式,如果确实需要,作者也帮我们实现了一个$set操作,这里就不做介绍了。

实现对象属性代理

正常情况下我们是这样实例化一个Vue对象:

var VM = new Vue({

data:{

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
中…(img-R82dtq90-1715655859955)]

[外链图片转存中…(img-EaDHk1yO-1715655859955)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值