很早之前就了解了数据劫持现,重温一下源码又有了新的理解主要还是了解里面的设计思想观察者模式
import Vue from ‘vue‘
let vm = new Vue({
el: ‘#app‘,
data () {
return {
title: ‘学生列表‘,
classNum: 1,
info:{
a:{
b: 1
}
},
teachers: [‘张三‘,‘李四‘],
students: [
{
id: 1,
name:‘小红‘
},
{
id: 2,
name: ‘小明‘
}
]
}
}
})
写项目写多了感觉没提升就得看看源码,提高下自己的素养。经常这样写vue2.0,new出一个vue对象里面是一个对象里面有很多的options例如data,computed等 vue2.0实际上都是一些options api,这样的api对于开发来说能够做的选择却不是特别多所以在3.0中将大部分都改成了composition api让开发人员有了更多的选择很大一部和react类似在3.0中的数据劫持用了es6中的Proxy
中的新方法很大程度上优化了2.0中的响应式数据。在2.0当中vue底层用到的defineProperty
对对象进行了处理这个方法不能对数组进行一个劫持,所以重写数组的几种方法,对于数组在原型上重新定义了所有的方法,会造成代码臃肿,现在大部分的浏览器都支持es6所以在vue3中直接使用了es6的Proxy
方法对于项目性能来说是很大的提升。
来了解下vue2中最基本的响应式数据理念 对于data中的数据进行了下面方式的处理
import proxyData from ‘./proxy‘
import observe from ‘./observe‘
function initState (vm) {
var options = vm.$options
if(options.data) {
initData(vm)
}
}
function initData (vm) {
var data = vm.$options.data
data = vm._data = typeof data === ‘function‘ ? data.call(vm) : data || {}
for (var key in data){
proxyData(vm, ‘_data‘, key)
}
observe(vm._data)
}
export {
initState
}
function proxyData (vm, target, key) {
Object.defineProperty(vm, key, {
get () {
// console.log(‘proxy data: ‘ + vm[target][key])
return vm[target][key]
},
set (newValue) {
vm[target][key] = newValue
}
})
}
export default proxyData
这就是为什么我们写的数据是一个函数为什么能用vm.title
访问到我们的标题。
在初始化函数之中直接对这个函数进行条用并且把这个值赋给了vm._data
,在对整个数据进行一层代理用到了defineProperty这个es5中的方法只要我们去访问就会走到get这个函数。但是这样坐下来我们只是对于我们的data中的第一层数据进行了响应式处理。 我们来刨析这个问题如何让所有数据都能够获得响应式,数据的情况可能有一下几种,data({})
中的这个对象里面可能有数组我们需要对这个数组的方法重写,数组里面还有对象,对象里面有对象嵌套多种情况,只需要递归对于整个数据进行分类我们就能够对于整体数据进行响应式绑定,利用到观察者模式
import Observer from ‘./observer‘
function observe (data) {
if(typeof data !== ‘object‘ || data === null) return
return new Observer(data)
}
export default observe
import defineReactiveData from ‘./reactive‘
import { arrMethdos } from ‘./array‘
import observeArr from ‘./observeArr‘
function Observer (data) {
if(Array.isArray(data)){
data.__proto = arrMethdos
observeArr(data)
}
else {
this.walk(data)
}
}
Observer.prototype.walk = function (data) {
var keys = Object.keys(data)
// console.log(keys)
for (var i = 0; i < keys.length; i++){
var key = keys[i],
value = data[key]
defineReactiveData(data, key, value);
}
}
export default Observer
暂时不去分析是函数的情况 我们首先对于非数组进行讨论,源码中用到walk这个方法就是一个简单的循环遍历 只是给封装了起来我们能够取到key值value那么我们就能够直接进行一个defineReactiveData
操作(一个definePropertyde
的扩展性封装)
function defineReactiveData (data, key, value){
observe(value);
Object.defineProperty(data, key, {
get () {
console.log(‘响应式获取‘, value)
return value;
},
set (newValue) {
// console.log(‘响应式设置‘, newValue)
if(newValue === value) return
observe(newValue)
value = newValue
}
})
}
这样递归我们就能够是整个过程都能够变成响应式数据。接下来就剩下数组的处理重写数组的7个方法
var ARR_METHODS = [
‘push‘,
‘pop‘,
‘shift‘,
‘unshift‘,
‘splice‘,
‘sort‘,
‘reverse‘
]
import { ARR_METHODS } from ‘./config‘
import observeArr from ‘./observeArr‘
var originArrMethods = Array.prototype,
arrMethdos = Object.create(originArrMethods)
ARR_METHODS.map(function (m) {
arrMethdos[m] = function () {
var args = Array.prototype.slice.call(arguments),
rt = originArrMethods[m].apply(this, args)
var newArr
switch (m) {
case ‘push‘:
case ‘unshift‘:
newArr = args;
break
case ‘splice‘:
newArr = args.slice(2)
break
default:
break;
}
newArr && observeArr(newArr)
return rt
}
})
function observeArr (arr) {
for (var i = 0; i < arr.length; i++){
observe(arr[i])
}
}
我们重写这些数组方法后得到的新数据我们还要进行遍历对于里面的所有数据还要加上一层响应式
这就是整个vue2中数据劫持的整理过程难点主要还是在对于数组的处理上 es6中的Proxy
的引入可以使得整个的代码可读性更强。
个人在对于VUE学习的小笔记,弱鸡一个
原文:https://www.cnblogs.com/xieshaoxiong/p/14729562.html