Bootstrap

Class、Reflect、Proxy及Vue响应式

Class

        JavaScript中类的定义及继承,extends 实现对对象的继承,super用于实现父类中的constructor方法,并将参数传递给父类。


// 人类
class people {
  _name;
  _age;
  get name() {
    return this._name
  }
  set name(newval) {
    this._name = newval
  }
  get age() {
    return this._age
  }
  set age(newval) {
    this._age = newval
  }
  sleep() {
    console.log(`${this._name}在睡觉`);
  }
  static isPeople(key) {
    Reflect.has(this, key) && console.log(`${key} in people`);
  }
  constructor(name, age) {
    this._age = age;
    this._name = name;
  }
}
// 教师类
class teacher extends people {
  grade;
  curse;
  teach() {
    console.log(`${this.name}在好好教${curse}!!`);
  }
  static play() {
    console.log("教师有寒暑假");
  }
  constructor(name, age, grade, curse) {
    super(name, age);
    this.grade = grade;
    this.curse = curse;
  }
}
//学生类
class student extends people {
  grade;
  curse;
  study() {
    console.log(`${this.name}在好好学习!!`);
  }
  static play() {
    console.log("学生都需要运动");
  }
  constructor(name, age, grade, curse) {
    super(name, age);
    this.grade = grade;
    this.curse = curse;
  }

}

Reflect:

       Reflect是JavaScript中的全局对象,提供操作JavaScript对象的方法,类似与Object操作对象的方法。用于解决Object方法过于臃肿的问题,对大多数的Object方法进行了实现,同时对于对象的操作返回操作的结果,如返回对象的set操作结果,在某些场景下可以进行监听操作。

Proxy:

        Proxy是一个js类,用于实现对对象的代理操作避免直接操作原始数据对象。


const objProxy = new Proxy(student1, {
  set(target, key, value, receiver) {
    console.log('target,key,value,receiver', target, key, value, receiver);
  },
  get(target, key, receiver) {
    console.log('target,key,value,receiver', target, key, receiver);
  },
  has(target, key) {
    console.log('判断对象是否含有该属性');
  },
  getPrototypeOf() {
    console.log('获取对象的原型');
  },
  getOwnPropertyDescriptor() {},
  setPrototypeOf() {
    console.log('设置原型继承');
  },
  isExtensible() {
    console.log('判断对象属性是否可以扩展');
  },
  defineProperty() {
    console.log('监听对象属性描述符');
  },
  deleteProperty() {
    console.log("删除对象属性操作");
  },
  apply(target, thisArg, argArray) {
    return target.apply(thisArg, argArray)
  },
  construct(target, argArray, newTarget) {
    return new target(...argArray)
  }
})

Vue2中响应式实现的原理。

        利用Object.defineProperty()接口实现对对象的监听。


const obj = {
  name:'peter',
  age:18,
  foo1:function(){
  console.log('我是obj对象的方法')
  }
}
Object.keys(obj).forEach(key => {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    get() {
      console.log(`获取了${key}属性`);
      return value
    },
    set(newValue) {
      value = newValue;
      show(key)
      console.log(`设置了${key}的值---${newValue}`);
    }
  })
})
function show(params) {
  console.log(`监听到${params}发生改变的function`);
}
console.log(obj.name); // 监听到name发生改变的function
                       //response.js:131 设置了name的值---alison
obj.foo1();//获取了foo1属性
           //response.js:115 我是obj对象的方法>>>

利用Object.defineProperty()实现监听的缺陷。

     1、Object.defineProperty()API设计的初衷不是为了实现对对象的监听,是为了对对象的属性进行修改定义,如enumerable,writable,configurable等。

     2、对于对象属性的添加和删除监听需要搭配其它方法进行,无法直接实现。

Vue3中响应式的实现原理:

核心思想:

       利用Proxy的代理操作内的getset,对对象属性的访问及改变进行监听,利用代理对象每次访问get操作的targetkey,在全局对象中找寻代理对象属性相应的依赖函数或方法,执行依赖函数或方法。

First:

        创建依赖收集类:用于收集对象属性对应的依赖函数或方法。


class Depend{
  constructor(){
    this.activeReactiveFns = new Set();
  };
  add(){
    if(activeReactiveFn){
      this.activeReactiveFns.add(activeReactiveFn)
    }
  };
  notify(){
    this.activeReactiveFns.forEach(_=>_())
  }
}

Second:

        封装函数实现传递targetkey返回对象属性对应的依赖对象depend。


const targetWeakMap = new WeakMap;
funciton getDepend(target,key){
  let map = targetWeakMap.get(tagget);
  if(!map){
    const map = new Map();
    targetWeakMap.set(target,map)
  }
  let depend = map.get(key);
  if(!depend){
    depend  = new Depend;
  }
  return depend
}

Third:

    封装函数收集对象属性依赖。


let activeReactiveFn = null;
watchFn(fn){
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}

Fourth:

    封装函数,利用Proxy的捕获器将目标对象转化为响应式对象reactiveObj


function ReactiveObj(target){
  return new Proxy(target,{
    get(target,key,receiver){
      const depend = getDepend(target,key);// 收集依赖函数
      depend.add();
      return Reflect.get(target,key,receiver);
    },
    set(target,key,newval,receiver){
      Reflect.set(target,key,newval);
      const depend = getDepend(target,key);
      depend.notify(); // 执行依赖函数
    }
  })
}

Last:

        将需要监听的对象转化为响应式对象,添加响应式函数。


const obj ={
  name:'Alison',
  age:22
}
const objProxy = Reactive(obj);
watch(_=>{
console.log(objProxy.name); // 收集依赖
})
obj.name = 'Alen';

        结合Class使用实际效果,响应式对象属性发生变化时,执行相应的依赖函数。

// 人类
class people {
  _name;
  _age;
  get name() {
    return this._name
  }
  set name(newval) {
    this._name = newval
  }
  get age() {
    return this._age
  }
  set age(newval) {
    this._age = newval
  }
  sleep() {
    console.log(`${this._name}在睡觉`);
  }
  static isPeople(key) {
    Reflect.has(this, key) && console.log(`${key} in people`);
  }
  constructor(name, age) {
    this._age = age;
    this._name = name;
  }
}
// 教师类
class teacher extends people {
  grade;
  curse;
  teach() {
    console.log(`${this.name}在好好教${curse}!!`);
  }
  static play() {
    console.log("教师有寒暑假");
  }
  constructor(name, age, grade, curse) {
    super(name, age);
    this.grade = grade;
    this.curse = curse;
  }
}
//学生类
class student extends people {
  grade;
  curse;
  study() {
    console.log(`${this.name}在好好学习!!`);
  }
  static play() {
    console.log("学生都需要运动");
  }
  constructor(name, age, grade, curse) {
    super(name, age);
    this.grade = grade;
    this.curse = curse;
  }

}
const s1 = new student('alison', 24, '三年级', 'English');
const t1 = new teacher('alin', 32, '高一', 'physical');
// 响应式监听对象属性的访问与修改
let activeReactiveFn = null;
// 全局收集依赖对象
const targetMap = new WeakMap();
// 依赖收集类
class Depend {
  constructor() {
    this.activeReactiveFns = new Set();
  };
  addDepend(...fn) {
    this.activeReactiveFns.add(...fn)
  };
  add() {
    if (activeReactiveFn) {
      this.activeReactiveFns.add(activeReactiveFn);
    }
  };
  notify() {
    this.activeReactiveFns.forEach(_ => _())
  }
}
// 全局搜集依赖函数
function getDepend(target, key) {
  let map = targetMap.get(target);
  if (!map) {
    map = new Map;
    targetMap.set(target, map);
  }
  let depend = map.get(key);
  if (!depend) {
    depend = new Depend;
    map.set(key, depend);
  }
  return depend
}
// 响应式函数封装
function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}

// 添加对象为响应式对象
function addProxyDepend(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      // 根据target.key获取对应的depend
      const depend = getDepend(target, key);
      //给对应的depend收集依赖
      depend.add();
      return Reflect.get(target, key, receiver)
    },
    set(target, key, newval, receiver) {
      Reflect.set(target, key, newval, receiver);
      //获取对象对应的依赖
      const depend = getDepend(target, key);
      // 执行依赖函数
      depend.notify();
    }
  })
}
// 创建对t1象代理
const t1Proxy = addProxyDepend(t1);
const s1Proxy = addProxyDepend(s1);
// 创建s1对象代理
function foo1() {
  console.log('ts1.age监听1', t1Proxy.age);
}

// watchFn(foo1)
watchFn(function () {
  console.log('t1Proxy.name监听', t1Proxy.name);
})

t1Proxy._name = 'peter';

(function name(params) {
  let calc = 0;
  setInterval(() => {
    calc += 1;
    t1Proxy._name = calc
  }, 3000)
})()

;