全国哪个县网站做的最好网站关键词排名系统
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:53
当前位置: 首页 > news >正文
全国哪个县网站做的最好,网站关键词排名系统,网站健设推广产品多少钱,wordpress code如果您觉得这篇文章有帮助的话#xff01;给个点赞和评论支持下吧#xff0c;感谢~ 作者#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来
书籍给个点赞和评论支持下吧感谢~ 作者前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来
书籍《Vue.js设计与实现》 作者霍春阳
本篇博文将在书第5.1节至5.4节的基础上进一步总结所提到的基础概念附加了测试的代码运行示例方便正在学习Vue3或想分析Vue3源码的朋友快速阅读
如有帮助不胜荣幸
前文 Vue3.js“非原始值”响应式实现基本原理笔记一
如何代理Object
“读取”是一个很宽泛的概念原文
在之前的笔记中只简单的讨论了如obj.foo这般获取对象属性值的读取但读取有很多种例如下面几种
访问属性obj.foo判断key in obj遍历for (const key in obj)…
这一章的内容就是针对这几种不同的读取以及其他的常见行为如删除等进行拦截
实现的逻辑主要是看操作符对应的拦截函数
在书中是通过查阅ECMA规范明确操作符运行逻辑进而找到操作符的运算结果是调用什么抽象方法然后通过这个抽象方法找到对应的内部方法进而对比Vue3.js“非原始值”响应式实现基本原理笔记一提到的Proxy内部方法表选取对应的方法拦截
拦截 in
下面仅以in操作符为例我们来看一下书中是如何逐步找到拦截方法的
在ECMA-262规范的13.10.1原文找到in操作符的运行时逻辑
让 lref 的值为 RelationalExpression 的执行结果。让 lval 的值为 ? GetValue(lref)。让 rref 的值为 ShiftExpression 的执行结果。让 rval 的值为 ? GetValue(rref)。如果 Type(rval) 不是对象则抛出 TypeError 异常。返回 ? HasProperty(rval, ? ToPropertyKey(lval))。
关键是第6步出现了HasProperty()然后在在ECMA-262规范的7.3.11原文找到关于这个方法的逻辑
断言Type(O) 是 Object。断言IsPropertyKey§ 是 true。返回 ? O.[[HasProperty]] §。
可以发现这个内部方法[[HasProperty]]然后在表中找到对应的拦截函数——has如下图所示 然后就可以在Proxy的handler中使用has进行拦截了代码如下
const obj { foo: 1 }
const p new Proxy(obj, {has(target, key) {track(target, key)return Reflect.has(target, key)}
})effect(() {foo in p // 将会建立依赖关系
})在第5章有非常多的关于ECMA的运行时逻辑在书中没有解释所以笔者在这里还是简单介绍一下一些关键词以上述in的运行时逻辑为例
RelationalExpression关系表达式例如、、、in、instanceof、、等操作符在这里指的操作符in的左侧的表达式ShiftExpression位移操作的表达式操作符in的右侧的表达式lref和lvalRelationalExpression会生成一个引用lref然后通过GetValue(lref)得到lvalrref和lref逻辑同上
拦截 for…in遍历所有可枚举属性
逻辑和in是相同的找规范找到最后发现可以使用ownKey()去拦截
但是在ownKey中会做一些处理代码如下
const obj { foo: 1 }
const ITERATE_KEY Symbol()const p new Proxy(obj, {ownKeys(target) {// 将副作用函数与 ITERATE_KEY 关联track(target, ITERATE_KEY)return Reflect.ownKeys(target)}
})注这本书的特点就是类似于电视连续剧整一章节的内容是不断累积的所以看的时候不要间断同时要多复习
在之前的笔记中track是传入target和key代码如下
function track(target, key) {// 没有 activeEffect直接 returnif (!activeEffect) return;let depsMap bucket.get(target);if (!depsMap) {bucket.set(target, (depsMap new Map()));}let deps depsMap.get(key);if (!deps) {depsMap.set(key, (deps new Set()));}const array Array.from(deps);deps.add(activeEffect);activeEffect.deps.push(deps);
}现在变成了传入ITERATE_KEYiterate的意思是重复
为什么传入ITERATE_KEY?
因为ownKeys是用来获取一个对象的所有键不是与任何具体的键进行绑定所以就定义一个ITERATE_KEY作为标识去与副作用函数进行绑定
那么当触发的时候也同样需要传入ITERATE_KEY代码如下
trigger(target, ITERATE_KEY)这里需要注意的是遍历是遍历触发拦截是触发拦截整个过程只会触发一次ownKeys可以理解为执行到for..in时就触发拦截然后for…in循环遍历自身可枚举的属性
添加属性对for…in的影响
在上述代码中当执行p.bar2时for…in就会由循环一次变为两次因为obj变为了两个键但此时不会触发与ITERATE_KEY关联的副作用函数
原因非常简单执行p.bar2关联的是与bar相关联的副作用函数
解决的方法也非常简单在trigger中把两者都添加到effectsToRun
function trigger(target, key) {const depsMap bucket.get(target)if (!depsMap) return// 取得与 key 相关联的副作用函数const effects depsMap.get(key)// 取得与 ITERATE_KEY 相关联的副作用函数const iterateEffects depsMap.get(ITERATE_KEY)const effectsToRun new Set()// 将与 key 相关联的副作用函数添加到 effectsToRuneffects effects.forEach(effectFn {if (effectFn ! activeEffect) {effectsToRun.add(effectFn)}})// 将与 ITERATE_KEY 相关联的副作用函数也添加到effectsToRuniterateEffects iterateEffects.forEach(effectFn {if (effectFn ! activeEffect) {effectsToRun.add(effectFn)}})effectsToRun.forEach(effectFn {if (effectFn.options.scheduler) {effectFn.options.scheduler(effectFn)} else {effectFn()}})
}这里的ITERATE_KEY是外部定义的Symbol
target即遍历的obj
修改属性对foo…in的影响
修改属性不会对foo…in产生影响但需要注意的是修改属性和新增属性使用的都是[[Set]]所以需要做个区分代码如下
const p new Proxy(obj, { // 拦截设置操作set(target, key, newVal, receiver) {// 如果属性不存在则说明是在添加新属性否则是设置已有属性const type Object.prototype.hasOwnProperty.call(target, key) ? SET : ADD;// 设置属性值const res Reflect.set(target, key, newVal, receiver);// 将 type 作为第三个参数传递给 trigger 函数trigger(target, key, type);return res;},// 省略其他拦截函数
});然后再在trigger中进行判断如果是ADD时才执行depsMap.get(ITERATE_KEY)代码如下
function trigger(target, key, type) { // 省略其他逻辑// 只有当操作类型为 ADD 时才触发与 ITERATE_KEY 相关联的副作用函数 if (type ADD) { const iterateEffects depsMap.get(ITERATE_KEY); iterateEffects iterateEffects.forEach(effectFn {if (effectFn ! activeEffect) {effectsToRun.add(effectFn);}});}
}在书中还提到了定义枚举类型的重要性
const TriggerType {SET: SET,ADD: ADD
};便于后期维护
删除属性对for…in的影响
在书中通过查阅规范得知是通过deleteProperty去拦截的所以代码如下
const p new Proxy(obj, { deleteProperty(target, key) { // 检查被操作的属性是否是对象自己的属性 const hadKey Object.prototype.hasOwnProperty.call(target, key); // 使用 Reflect.deleteProperty 完成属性的删除 const res Reflect.deleteProperty(target, key); if (res hadKey) { // 只有当被删除的属性是对象自己的属性并且成功删除时才触发更新 trigger(target, key, DELETE); } return res; }
});这里手写是进行了一个判断删除的属性是否属于自身这是因为执行的逻辑可能是如delete p.a执行了但是这个属性不存在所以需要进行一个判断
那么最后就是在trigger中继续加多一个type判断代码如下
function trigger(target, key, type) { // 省略其他逻辑// 只有当操作类型为 ADD 或 DELETE 时才触发 if (type ADD || type DELETE) { const iterateEffects depsMap.get(ITERATE_KEY); iterateEffects iterateEffects.forEach(effectFn {if (effectFn ! activeEffect) {effectsToRun.add(effectFn);}});}
}其实看到这里能够发现在设计时是从CURD去考虑的不同情况
总结
这篇笔记主要复习了不同读取情况下的响应式实现
如何拦截in操作符如何拦截for…in操作符当新增、修改和删除时如何实现响应式
- 上一篇: 全国拿货最便宜的网站建商城网站
- 下一篇: 全国企业名录大全seo岗位有哪些
相关文章
-
全国拿货最便宜的网站建商城网站
全国拿货最便宜的网站建商城网站
- 技术栈
- 2026年03月21日
-
全国门户网站有哪些做直播教程的网站有哪些
全国门户网站有哪些做直播教程的网站有哪些
- 技术栈
- 2026年03月21日
-
全国门户网站有哪些宣传推广费用预算
全国门户网站有哪些宣传推广费用预算
- 技术栈
- 2026年03月21日
-
全国企业名录大全seo岗位有哪些
全国企业名录大全seo岗位有哪些
- 技术栈
- 2026年03月21日
-
全国网站备案wordpress jsdelivr
全国网站备案wordpress jsdelivr
- 技术栈
- 2026年03月21日
-
全国网站建设公谷歌网站英文
全国网站建设公谷歌网站英文
- 技术栈
- 2026年03月21日






