前置技术点
1、数组reduce()方法
应用场景:下次操作的初始值,依赖于上次操作的返回值
- 数值的累加计算
//一个数组的所有项累加
const arr = [2,3,4,6,2,12,34,56];
// 一般实现方案
let total = 0;
arr.forEach((item) => {
total += item;
})
console.log('total--',total);
// 数组的reduce方法,会循环当前的数组,侧重于进行“滚雪球”操作
// 数组.reduce(函数,初始值)
// 数组.reduce ((上次计算的结果,当前循环的Item项) => {},0)
// const 累加的结果 = 数组.reduce((上次计算的结果,当前循环的Item项) => {return 上次的结果+ 当前循环的Item项},0)
const total2 = arr.reduce((val,item)=>{
return val+ item;
})
console.log('total2--',total2);
- 链式获取对象属性的值
2、发布订阅模式
- Dep类
- 负责进行依赖收集
- 首先,有个数组,专门用来存放所有的订阅信息
- 其次,还要提供一个向数组中追加订阅信息的方法
- 最后,还要提供一个循环,循环触发数组中的每个订阅信息
注:只要我们为Vue中data数据重新赋值了,这个赋值的动作,会被Vue监听到,
然后vue要把数据的变化通知每个订阅者,
接下来,订阅者(DOM元素)要根据最新的数据,更新自己的内容
- Watcher 类
- 负责订阅一些事件
3、 使用object.defineProperty()进行数据劫持
1. 通过get()
劫持取值操作
2. 通过set()
劫持赋值操作
//定义一个数据劫持的方法
function Observe(obj){
//这是递归的终止条件
if(!obj || typeof obj!='object') return;
//通过Object.keys(obj)获取当前obj上的每个属性
Object.keys(obj).forEach((key) => {
//当前被循环的key所对应的属性值
let value = obj[key];
//当前被循环的key所对应的属性值
Observe(value);
//需要为当前的key所对应的属性,添加getter和setter
Object.defineProperty(obj,key,{
enumerable: true,
configurable: true,
get(){
// console.log(`有人获取了${key}的值`);
return value;
},
set(newVal){
value = newVal;
Observe(value);
}
})
})
}
为什么methods对象下的法可以通过this获得data下的属性
//属性代理
object.key((this.$data).forEach((key) => {
object.defineProperty(this,key,{
enumerable: true,
configurable: true,
get(){
return this.$data[key];
},
set(newValue){
this.$data[key] = newValue;
}
})
}))
对html结构进行模板编译
//对html结构进行模板编译的方法
function Compile(el,vm){
//获取el对应的DOM元素
vm.$el = document.querySelector(el);
//创建文档碎片,提高DOM操作的性能
const fragment = document.createDocumentFragment();
while ((childNode = vm.$el.firstChild)){
fragment.appendChild(childNode)
}
//进行模板编译
vm.$el.appendChild(fragment);
}
//负责对DOM模板进行编译的方法
function replace(){
//定义匹配插值表达式的正则
const regMustache = /\{\{\s*(S+)\s*\}\}/
//证明当前的node节点是一个文本子节点,需要进行正则的替换
if(node.nodeType === 3){
//注意:文本子节点,也是一个DOM对象,如果要获取文本子节点的字符串内容,需要调用textContent属性获取
const text = node.textContent;
const execResult = regMustache.exec(text);
console.log(execResult)
if(execResult){
const value = execResult[1].split('.').reduce((newObj,k)=>newObj[k],vm);
node.textContent = text.replace(regMustache,value)
}
//终止递归的条件
return
}
//证明不是文本节点,可能是一个DOM元素,需要进行递归处理
node.childNodes.forEach((child) => replace(child));
}
最简单的发布订阅
// 最简单的发布订阅模式
// 收集依赖/收集订阅者
class Dep {
constructor(){
//这个subs数组,用来存放所有订阅者的信息
this.subs = [];
}
//向subs数组中,添加订阅者信息
addSub(watcher){
this.subs.push(watcher);
}
// 发布通知的方法
notify(){
this.subs.forEach((watcher) => watcher.update());
}
}
//订阅者的类
class Watcher{
// cb回调函数中,记录着当前Watcher如何更新自己的文本内容
// 但是,只知道如何更新自己还不行,还必须拿到最新的数据
// 因此 还需要在new Watcher 期间,把vm 也传递过来(因为vm中保存着最新的数据)
// 除此之外,还需知道,在vm身上众多数据中,哪个数据,才是当前自己需要的数据
// 因此, 必须在new Watcher期间,指定watcher对应的数据名字
constructor(vm,key,cb){
this.vm = vm;
this.key = key;
this.cb = cb;
}
// watcher 的实例,需要有update函数,从而让发布者能够通知我们进行更新
update(){
this.cb()
}
}
const w1 = new Watcher(() =>{
console.log('我是第一个订阅者')
})
网友评论