对象的响应式原理
利用闭包来实现defineReactive函数的封装,避免需要提前定义变量才可以实现set函数:
let obj = {}
// let item 不需要在提前定义变量
function defineReactive(data, key, val) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
return val
},
set(newVal) {
val = newVal
}
})
}
defineReactive(obj, 'a', 5)
obj.a = 9
console.log(obj.a)
复制代码
对象的一个循环递归图:
类 Observer作用
:将一个正常的object转换为每个层级的属性都是响应式(可以被侦测)的。
index.js
import { observe } from './observe'
let obj = {
a: {
m: {
n: 5
}
},
b: 10
}
observe(obj)
console.log(obj.a.m.n)
复制代码
observe: 就是为了在调用类Observer的之前,进行判断,看是否需要进行Observer
import Observer from './Observer'
export const observe = (value) => {
if (typeof value != 'object') return
var ob
if (typeof value.__ob__ !== 'undefined') {
ob = value.__ob__
} else {
ob = new Observer(value)
}
return ob
}
复制代码
Observer类:利用defineReactive,对属性进行循环遍历绑定getter、setter
import { def } from './utils'
import defineReactive from './defineReactive'
export default class Observer {
constructor(value) {
def(value, '__ob__', this, false)
this.walk(value)
}
// 遍历
walk(value) {
for (const k in value) {
defineReactive(value, k)
}
}
}
复制代码
defineReactive :利用闭包,不需要在使用变量(上面有讲到),给属性绑定getter和setter
import { observe } from './observe'
export default function defineReactive(data, key, val) {
console.log(data, key, 999)
if (arguments.length == 2) {
val = data[key]
}
let childOb = observe(val)
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
console.log('试图访问' + key)
return val
},
set(newVal) {
val = newVal
childOb = observe(newVal)
}
})
}
复制代码
util.js :在类Observer中使用,为了给每个属性绑定__ob__
属性,同时设置enumerable
export const def = (obj, key, value, enumerable) => {
Object.defineProperty(obj, key, {
value,
enumerable,
writable: true,
configurable: true
})
}
复制代码
数组的响应式原理
对数组的7个函数进行重写,利用Object.setPrototypeOf方法进行处理,将这些方法的原型指向变异后的数组。但是我们原生的数组方法并不能丢失,我们需要复制取得原声的数组方法,在监听的时候进行apply改变this指向,传入arguments,调用复制的原生方法处理。说白了,就是要利用原生数组方法的功能,变异为可以被监听的方法
。
['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']
复制代码
//看看就行了,不完整
const nums = [1,2,3];
const ArrayProto = Array.prototype;
const arrayArguments = [];
const ArrayMethods = ['push'];
ArrayMethods.forEach((method) => {
// 原生方法
let orginal = ArrayProto[method];
arrayArguments[method] = function() {
console.log('push');
return orginal.apply(this, arguments);
}
})
// 重点
nums.__proto__ = arrayArguments;
nums.push(1);
console.log(nums)
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END