此前在看尤大大的视频时对其介绍vue Object.defineProperty属性方法的一些尝试,再次将其方法搬出来同时加一些自己的注解。也许代码备注有所错误,请大佬指出。
<script>
// 尝试双向数据绑定
// 首先定义一个方法用来数据劫持
function observe(obj) {
// 判断是否为obj
if (!isObject(obj)) {
// 抛出错误
throw new TypeError()
}
// 在这里对obj进行循环
// 因为Object.defineProperty需要对key值进行监听
Object.keys(obj).forEach(key => {
// 创建一个内部变量
let internalValue = obj[key]
// 创建一个dep 实例
let dep = new Dep()
// 使用Object.defineProperties 进行数据监听
// 在这里对gei 和set 方法进行重构
Object.defineProperty(obj, key, {
// 获取数据并返回
get() {
dep.depend()
console.log(activeUpdate,'更新状态activeUpdate');
// 将获取到的数据进行返回
return internalValue
},
// 设置数据
set(newValue) {
console.log(newValue,'改变的值newValue');
const isChanged = internalValue !== newValue
if (isChanged) {
internalValue = newValue
dep.notify()
}
}
})
})
}
// 在这里对dep进行声明创建
window.Dep = class Dep {
constructor() {
// 声明一个变量 订阅者
this.subscribers = new Set()
}
// 同时此方法还应该有 依赖和通知
depend() {
// 通知判断状态
if (activeUpdate) {
// 将当前活动更新注册为订阅者
this.subscribers.add(activeUpdate)
}
}
// 通知
notify() {
// 运行所有订阅函数
console.log(this.subscribers,'所有的属性');
this.subscribers.forEach(subscriber => {
subscriber()
console.log(subscriber,'方法');
})
}
}
let activeUpdate
// 一个自动执行的方法
function autorun(update) {
function wrappedUpdate() {
activeUpdate = wrappedUpdate
// 再此调用 输入的方法也就是对响应式触发
update()
activeUpdate = null
}
wrappedUpdate()
}
// 一个判断是否为obj的方法
function isObject(obj) {
return typeof obj === 'object'
&& !Array.isArray(obj)
&& obj !== null
&& obj !== undefined
}
// 定义一个对象
let state = {
count: 0
}
/**当执行这个方法时,会首先判断是否为obj 如果是则对state 键值对(属性名)进行循环
*然后为每个属性名创建一个dep class 然后用 object.defineProperty进行监听
本质上当调用或者修改当前数据的时候都会进行监听,这也就是为什么activeUpdate 存在的必要
defineProperty 方法 首先会在get方法也就是获取值的时候 调用 depend方法 将参数注册到订阅者里
同时在set 方法时判断数据是否改变同时通知notify 来进行操作 也就是运行 autorun 方法即自动执行
**/
observe(state)
autorun(() => {
window.console.log(`count is: ${state.count}`)
})
// console.log(state.count);
state.count++