Vue 核心之数据劫持(1),从基础到源码统统帮你搞定

}

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
img
img
img
img
img

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

总结

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

JavaScript

性能

linux

前端面试题汇总**

CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

JavaScript

性能

linux

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值