Vue 核心之数据劫持

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:{

name:‘lhl’

},

el:‘#id’

})

按理说我们操作数据的时候应该是VM.data.name = ‘hxx’才对,但是作者觉得这样不够简洁,所以又通过代理的方式实现了VM.name = ‘hxx’的可能。 相关代码如下:

function proxy (vm, key) {

if (!isReserved(key)) {

Object.defineProperty(vm, key, {

configurable: true,

enumerable: true,

get: function proxyGetter () {

return vm._data[key]

},

set: function proxySetter (val) {

vm._data[key] = val;

}

});

}

}

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

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

[外链图片转存中…(img-t4XuIJ0u-1713567261750)]

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-1yPkVj1Z-1713567261750)]

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可免费获取,包括答案解析。

[外链图片转存中…(img-1eC0zEzQ-1713567261751)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值