第五章-非原始值地响应式方案(set和map)

59 阅读3分钟

set和map两种原型属性和方法

相同的方法

  • size
  • delete
  • has
  • clear
  • keys
  • values
  • entries
  • forEach

不同的方法

1、set

  • add

2、map

  • set
  • get

1、如何代理Set和Map

需要实现下面的代码

const proxy = new Proxy (new Map([['key', 1]]))
effect(() => {
   console.log(proxy.get('key'))
})
proxy.set('key', 2);

根据Array的经验来说, 一般会跟size相关

const s = new Set([1,2,3])
const p = new Proxy(s, {})
p.size

上面代码会报错, 因为size是一个访问器属性, 即{get size() { return xxx}} , 但是我们当面在get中设置了代理器为this对象

Reflect.get(target, key, recevier)

所以更改代理方法get

const s = new Set([1, 2, 3])
const p = new Proxy(s, {
    get(target, key, receiver) {
      if (key === 'size') {
        return Reflect.get(target, key, target)
       }
      // 读取其他属性的默认行为
       return Reflect.get(target, key, receiver)
      }
})

但是当测试delete方法的时候

p.delete(1)
// Uncaught TypeError: Method Set.prototype.delete called on incompatible receiver #<Set> at Proxy.delete

p.detele中的this是原生对象s, 但是p.detele(1)的this是代理对象

原因:

let obj = {foo: 1, getFoo: function ()  {console.log(this)}  }
obj.getFoo() // getFoo的this指向的就是obj, {foo: 1, getFoo: ƒ}

let p = new Proxy(obj, {}) 
p.getFoo() // getFoo的this指向的就是代理对象p, Proxy {foo: 1, getFoo: ƒ}

//为什么Reflect设置了receiver为target不起作用, 因为receiver只对get方法的this起作用, 如下面示例
let setObj = {
  value: 1,
  get size() {
    return this.value;
  },
}
Reflect.get(setObj, "size", {value: 2}) // 2;

需要把Reflect方法更改为bind

function isSetMap(target) {
  let idx = ["Set", "Map"].findIndex(type => Object.prototype.toString.call(target) === `[object ${type}]`)
  return idx !== -1;
}

get(target, key, receiver) {
      if(key === "raw") return  target;
      // 如果操作目标是set或者map
      if(isSetMap(target)) {
        if(key === "size") return Reflect.get(target, key, target);
        return target[key].bind(target);
      }
      // 如果操作目标是数据, 并key存在arrayInstrumentations上, 那么返回定义在arrayInstrumentations的中
      if(Array.isArray(target) && arrayInstrumentations.hasOwnProperty(key)) {
        // 为什么这里就直接返回, 因为不需要跟踪数组的方法
        return Reflect.get(arrayInstrumentations, key, receiver);
      }
      if(!isReadOnly && typeof key !== "symbol") {
        track(target, key);
      }
      let res = Reflect.get(target, key, receiver);
      if(isShallow) return res;
      if(typeof res === "object" && res !== null) {
        return isReadOnly ? readonly(res) : reactive(res);
      }
      return res;
}

2、建立响应关系

类似数组一样, 新增或者删除元素会影响set和map的size, 所以需要对size进行跟踪

if(isSetMap(target)) {
    if(key === "size")  {
        track(target, ITERATE_KEY)
        return Reflect.get(target, key, target)
    }
    return mutableInstrumentations[key];
 }

需要在调用方法的时候, 触发副作用函数

const mutableInstrumentations = {
  add(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.add(key);
    if(!hasKey) {
      trigger(target, key, "ADD");
    }
    return res;
  },
  delete(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.delete(key);
    if(!hasKey) {
      trigger(target, key, "DELETE");
    }
    return res;
  }
}


 new Proxy(data,  {
    // 对应obj.key
     get(target, key, receiver) {
      if(key === "raw") return  target;
      // 如果操作目标是set或者map
      if(isSetMap(target)) {
        if(key === "size")  {
          track(target, ITERATE_KEY)
          return Reflect.get(target, key, target)
        }
        return mutableInstrumentations[key];
      }
      if(Array.isArray(target) && arrayInstrumentations.hasOwnProperty(key)) {
        return Reflect.get(arrayInstrumentations, key, receiver);
      }
      if(!isReadOnly && typeof key !== "symbol") {
        track(target, key);
      }
      let res = Reflect.get(target, key, receiver);
      if(isShallow) return res;
      if(typeof res === "object" && res !== null) {
        return isReadOnly ? readonly(res) : reactive(res);
      }
      return res;
    },
    .....
 }

3、避免污染原始数据

按照set和map的方法对比可知, set拥有add方法, map拥有set和get方法, 同样需要实现

const mutableInstrumentations = {
  add(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.add(key);
    if(!hasKey) {
      trigger(target, key, "ADD");
    }
    return res;
  },
  delete(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.delete(key);
    if(!hasKey) {
      trigger(target, key, "DELETE");
    }
    return res;
  },
  set(key, newVal) {
    const target = this.raw;
    const hasKey = target.has(key);
    const oldVal = target.get(key);
    let res = target.set(key, newVal);
    if(!hasKey) {
      trigger(target, key, "ADD");
    } else if(newVal !== oldVal || (newVal === newVal &&  oldVal === oldVal)) { // 需要增加值的判断
      trigger(target, key, "SET");
    }
    return res;
  },
  get(key) {
    const target = this.raw;
    let hasKey = target.has(key);
    track(target, key)
    if(hasKey) {
      const res = target.get(key);
      return typeof res === "object" && res !== null ? reactive(res) : res;
    }
  }
}

污染表现: 通过原始对象访问内部键值能触发响应, 但是原始数据不应该具有响应式数据的能力

let m1 = new Map();
let p1 = reactive(m1);
let m2 = new Map();
let p2 = reactive(m2);
p1.set("p2", p2);
effect(() => {
  console.log(m1.get("p2").size)
})
m1.get("p2").set("foo", 1)

问题代码

 set(key, newVal) {
    const target = this.raw;
    const hasKey = target.has(key);
    const oldVal = target.get(key);
    let res = target.set(key, newVal);   // newVal原样设置到了原始数据target上面
    if(!hasKey) {
      trigger(target, key, "ADD");
    } else if(newVal !== oldVal || (newVal === newVal &&  oldVal === oldVal)) { // 需要增加值的判断
      trigger(target, key, "SET");
    }
    return res;
  },

总结: 把响应式数据设置到原始数据上的行为成为数据污染

解决

 set(key, newVal) {
    const target = this.raw;
    const hasKey = target.has(key);
    const oldVal = target.get(key);
    const rawVal = newVal.raw || newVal;
    let res = target.set(key, rawVal);   // 获取原始数据
    if(!hasKey) {
      trigger(target, key, "ADD");
    } else if(newVal !== oldVal || (newVal === newVal &&  oldVal === oldVal)) { // 需要增加值的判断
      trigger(target, key, "SET");
    }
    return res;
  },

4、处理forEach

遍历操作只会与键值对的数量有关, 因此任何修改Map对象的键值对的操作都应该触发副作用函数重新执行, 例如删除delete和add等, 因此应该让forEach被调用时候, 让副作用函数与ITERATE_KEY相关联

 const mutableInstrumentations = {
     forEach(callback) {
         const target = this.raw;
         track(target, ITERATE_KEY);
         target.forEach(callback)
      }
  }

上面的代码还有一下的问题

1、forEach传递给回调函数的参数是非响应数据

forEach(callback) {
    const wrap = (val) => typeof val === "object" ? reactive(val) : val;
    const target = this.raw;
    track(target, ITERATE_KEY);
    // callback接收三个参数, 1、当前的value, 2、当前的key, 3、正在被遍历的map对象
    target.forEach((value, key) => {
      callback(wrap(value), wrap(key), this)
    })
  }

2、forEach方法接受第二个参数, 用来指定callback函数执行时的this值

 forEach(callback, thisArg) {
    const wrap = (val) => typeof val === "object" ? reactive(val) : val;
    const target = this.raw;
    track(target, ITERATE_KEY);
    // callback接收三个参数, 1、当前的value, 2、当前的key, 3、正在被遍历的map对象
    target.forEach((value, key) => {
      callback.call(thisArg, wrap(value), wrap(key), this)
    })
  }

此外, forEach遍历不仅关心集合的键, 还关心集合的值, 所以除了ADD和DELETE操作外, SET操作也应该触发副作用函数重新执行, 下面是trigger函数的修改

function trigger(target, key, type, newVal) {
  let depsMap =  bucket.get(target);
  if(!depsMap) return;
  let effectsToRun = new Set();
  
  
  let effects = depsMap.get(key);
  effects && effects.forEach(effectFn => {
    if(effectFn !== activeEffect){
      effectsToRun.add(effectFn);
    }
  })
  
   .....
   
  let iterateEffects = depsMap.get(ITERATE_KEY);
  if(type === "ADD" || type === "DELETE" || (type === "SET" && isSetMap(target) )) {
    iterateEffects && iterateEffects.forEach(effectFn => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    })
  }
  
  effectsToRun.forEach(effectFn => {
    if(effectFn.options.scheduler){
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

5、迭代器方法

三个迭代器方法: 1、keys 2、values 3、entries

迭代器的内部实现都是通过[Symbol.iterator]实现

由于代理的原理, 同样[Symbol.iterator]需要放在mutableInstrumentations中

[Symbol.iterator]() {
     const target = this.raw;
     const itr = target[Symbol.iterator]();
     return itr; // 返回一个对象, 内部有next方法, next方法返回value和done
}

上面的代码存在跟forEach一样的问题, 迭代的值没有被代理, 是非响应数据, 需要修改成下面代码

[Symbol.iterator]() {
    const wrap = (val) => typeof val === "object" ? reactive(val) : val;
    const target = this.raw;
    const itr = target[Symbol.iterator]();
    // 返回自定义迭代器
    return {
      next() {
        const {value, done} = itr.next();
        return {
          value: value ? [wrap(value[0]), wrap(value[1])] : value,
          done
        }
      } 
    }
  }

以上只是解决了迭代值为非响应数据, 还没有对迭代器进行响应关系绑定

[Symbol.iterator]() {
    const wrap = (val) => typeof val === "object" ? reactive(val) : val;
    const target = this.raw;
    track(target, ITERATE_KEY); // 调用track函数建立响应关系
    const itr = target[Symbol.iterator]();
    // 返回自定义迭代器
    return {
      next() {
        const {value, done} = itr.next();
        return {
          value: value ? [wrap(value[0]), wrap(value[1])] : value,
          done
        }
      }
    }
  }

通过下面代码测试, 可以发现结合的响应式数据功能已经相对完整,下面是测试代码

const map = reactive(new Map([["bar",2]]))
effect(() => {
  for(const [key, value] of map ){
    console.log(key, value)
  }
})
map.set("foo", 1)
// bar 2
// bar 2
// foo 1

下面是set和map的等价关系, 通过[Symbol.iterator]可以实现对应的迭代器方法

const m = new Map()
m[Symbol.iterator] === m.entries  // true

const s = new Set()
s[Symbol.iterator] === s.values   // true
function iterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, ITERATE_KEY)
  const itr = target[Symbol.iterator]();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value: value ? [wrap(value[0]), wrap(value[1])] : value,
        done
      }
    }
  }
}
const mutableInstrumentations = {
  ....
  [Symbol.iterator]: iterationMethod,
  entries: iterationMethod,
}

但尝试用for...of进行迭代会报错

const map = reactive(new Map([["bar",2]]))
effect(() => {
  for(const [key, value] of map.entries() ){
    console.log(key, value)
  }
})
map.set("foo", 1)
// map.entities is not a function or its return value is not iterable
// p.entries的返回值不是一个可迭代对象, 一个可迭代对象应该具有Symbol.iterator方法
  • 可迭代协议指的是一个对象实现了Symbol.interator方法
  • 迭代器协议指的是一个实现了next方法

一个对象可同时实现可迭代协议和迭代器协议

const obj = {
   next() {}
   [Symbol.iterator]() {
     return this;
   }
}

同样处理iterationMethod方法

function iterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, ITERATE_KEY)
  const itr = target[Symbol.iterator]();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value: value ? [wrap(value[0]), wrap(value[1])] : value,
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

6、values和keys方法

跟entries类似, 但是存在不同

1、values

  • 关于迭代器对象, entries使用target[Symbol.iterator]获取, 而values使用target.values获取
  • next方法的值, entries处理的是键值对, 而values处理的是值
function valueIterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, ITERATE_KEY)
  const itr = target.values();
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value:  wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

2、keys

keys与values的差别有在, 前面在trigger有加过判断 type === "ADD" || type === "DELETE" || (type === "SET" && isSetMap(target) ), 当设置值的时候, 也会触发副作用函数, 但是这个keys没有影响, keys只对"ADD"和"DELETE"需要处理

const ITERATE_KEY = Symbol();
function  keyIterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, MAP_KEY_ITERATE_KEY)  // 重新定义个key值
  const itr = target.keys();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value:wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

trigger函数中需要加上对应的判断

if((type === "ADD" || type === "DELETE")  && isSetMap(target)) {
    let iterateEffects = depsMap.get(MAP_KEY_ITERATE_KEY);
    iterateEffects && iterateEffects.forEach(effectFn => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    })
  }

整体代码

const ITERATE_KEY = Symbol(); // 唯一个的key, 只需要建一个, 因为每个对象下面只会挂载一个ITERATE_KEY,  trigger的时间, 会先寻找对象, 后再寻找ITERATE_KEY。 可以理解对象不同, 但ITERATE_KEY相同
const MAP_KEY_ITERATE_KEY = Symbol();
let activeEffect // 当前副作用函数
let effectStack = []; // 副作用函数栈
function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    // 当调用effect注册副作用函数时,将副作用函数赋值给activeEffect
    activeEffect = effectFn;
    // 调用副作用函数之前将副作用函数压入栈
    effectStack.push(effectFn);
    let res =  fn()
    // 在当前副作用函数执行完成之后, 将当前副作用函弹出栈,并将activeEffect还原为之前的值
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  }
  // 将options挂载到effectFn上
  effectFn.options = options;
  // 用来所有与该副作用函数相关的依赖集合
  effectFn.deps = [];
  if(!options.lazy){
    effectFn();
  }
  return effectFn;
}

// 副作用函数依赖合集的删除
function cleanup(effectFn) {
  for(let i = 0; i < effectFn.deps.length; i++){
    let deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  effectFn.deps.length = 0;
}

// 桶,储存代理对象属性的相关事件
const bucket = new WeakMap();

// 跟踪函数
function track(target, key) {
  if(!activeEffect || !shouldTrack)  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())
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

// 触发函数
function trigger(target, key, type, newVal) {
  let depsMap =  bucket.get(target);
  if(!depsMap) return;
  let effectsToRun = new Set();
  
  
  let effects = depsMap.get(key);
  effects && effects.forEach(effectFn => {
    if(effectFn !== activeEffect){
      effectsToRun.add(effectFn);
    }
  })
  
  
  if(Array.isArray(target) && key === "length") {
    depsMap.forEach((effects, key) => {
      if(key >= newVal) {
        effects && effects.forEach(effectFn => {
          if(effectFn !== activeEffect){
            effectsToRun.add(effectFn);
          }
        })
      }
    })
  }
  
  
  if(Array.isArray(target) && type === "ADD") {
    let  lengthEffects = depsMap.get("length");
    lengthEffects && lengthEffects.forEach(effectFn => {
      if(effectFn !== activeEffect){
        effectsToRun.add(effectFn);
      }
    })
  }
  
 
  if(type === "ADD" || type === "DELETE" || (type === "SET" && isSetMap(target) )) {
    let iterateEffects = depsMap.get(ITERATE_KEY);
    iterateEffects && iterateEffects.forEach(effectFn => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    })
  }
  
  if((type === "ADD" || type === "DELETE")  && isSetMap(target)) {
    let iterateEffects = depsMap.get(MAP_KEY_ITERATE_KEY);
    iterateEffects && iterateEffects.forEach(effectFn => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    })
  }
  
  effectsToRun.forEach(effectFn => {
    if(effectFn.options.scheduler){
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}


function computed(getter) {
  let effectFn = effect(getter, {
    lazy:  true,
    scheduler() {
      dirty = true;
      trigger(obj, "value")
    }
  });
  let obj;
  let value;
  let dirty = true;
  obj = {
    get value() {
      if(dirty) {
        track(obj, "value");
        value = effectFn();
        dirty = false;
      }
      return value
    }
  }
  return obj;
}

function traverse(value, seen = new Set()) {
  if(typeof value !== "object" || value === null || seen.has(value)) return value;
  // 将数据添加到seen中, 代表遍历读取过了,避免循环引用引起的死循环
  seen.add(value)
  // 这里只考虑到了对象, 没有考虑到数组等结构体
  for(let key in value) {
    traverse(value[key], seen)
  }
  return value;
}

function watch(source, cb, options = {}) {
  let getter;
  if(typeof source === "function") {
    getter = source;
  } else {
    // 如果改为getter = traverse(source), 那么一开始就已经遍历obj下面的所有属性, 返回一个obj对象,
    // 后面effect中调用() => getter的时候, 访问的只是obj对象, 所有当对obj的对象进行设置的时候, 不起作用
    getter = () => traverse(source);
  }
  let newValue, oldValue;
  let cleanUp;
  function onInvalidate(cb) {
    cleanUp = cb;
  }
  const job = () => {
    newValue = effectFn();
    if(cleanUp) {
      cleanUp();
    }
    cb(newValue, oldValue, onInvalidate)
    oldValue = newValue;
  }
  let effectFn = effect(() => getter(), {
    lazy: true,
    scheduler() {
      if(options.flush === "post") {
        Promise.resolve().then(() => {
          job();
        })
      } else {
        job();
      }
    }
  })
  if(options.immediate) {
    job();
  } else {
    oldValue = effectFn();
  }
}

const arrayInstrumentations = {};
["includes", "indexOf", "lastIndexOf"].forEach(method => {
  arrayInstrumentations[method] = function(...args) {
    let originMethod = Array.prototype[method];
    let res = originMethod.apply(this, args) // 这里的this是虚拟对象, 因为方法是通过Reflect.get(.., receiver)调用的
    if(res === false || res === -1) {
      res = originMethod.apply(this.raw, args) // 如果没找到, 则通过this.raw拿到原始数组再去比对
    }
    return res;
  }
});
let shouldTrack = true;
["push", "pop", "push", "shift", "unshift"].forEach(method => {
  let originMethod = Array.prototype[method];
  arrayInstrumentations[method] = function(...args) {
    shouldTrack  = false;
    let res = originMethod.apply(this, args)
    shouldTrack = true;
    return res;
  }
})

function isSetMap(target) {
  let idx = ["Set", "Map"].findIndex(type => Object.prototype.toString.call(target) === `[object ${type}]`)
  return idx !== -1;
}


function iterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, ITERATE_KEY)
  const itr = target[Symbol.iterator]();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value: value ? [wrap(value[0]), wrap(value[1])] : value,
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}
function valueIterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, ITERATE_KEY)
  const itr = target.values();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value: wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

function  keyIterationMethod() {
  const wrap = (val) => typeof val === "object" ? reactive(val) : val;
  const target = this.raw;
  track(target, MAP_KEY_ITERATE_KEY)
  const itr = target.keys();
  // 返回自定义迭代器
  return {
    next() {
      const {value, done} = itr.next();
      return {
        value:wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}
const mutableInstrumentations = {
  add(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.add(key);
    if(!hasKey) {
      trigger(target, key, "ADD");
    }
    return res;
  },
  delete(key) {
    const target = this.raw;
    const hasKey = target.has(key);
    let res = target.delete(key);
    if(!hasKey) {
      trigger(target, key, "DELETE");
    }
    return res;
  },
  set(key, newVal) {
    const target = this.raw;
    const hasKey = target.has(key);
    const oldVal = target.get(key);
    const rawVal = newVal.raw || newVal;
    let res = target.set(key, rawVal);   // 获取原始数据
    if(!hasKey) {
      trigger(target, key, "ADD");
    } else if(newVal !== oldVal || (newVal === newVal &&  oldVal === oldVal)) { // 需要增加值的判断
      trigger(target, key, "SET");
    }
    return res;
  },
  get(key) {
    const target = this.raw;
    let hasKey = target.has(key);
    track(target, key)
    if(hasKey) {
      const res = target.get(key);
      return typeof res === "object" && res !== null ? reactive(res) : res;
    }
  },
  forEach(callback, thisArg) {
    const wrap = (val) => typeof val === "object" ? reactive(val) : val;
    const target = this.raw;
    track(target, ITERATE_KEY);
    // callback接收三个参数, 1、当前的value, 2、当前的key, 3、正在被遍历的map对象
    target.forEach((value, key) => {
      callback.call(thisArg, wrap(value), wrap(key), this)
    })
  },
  [Symbol.iterator]: iterationMethod,
  entries: iterationMethod,
  values: valueIterationMethod,
  keys: keyIterationMethod,
}

function createReactive(data, isShallow = false, isReadOnly = false) {
  return new Proxy(data,  {
    // 对应obj.key
    get(target, key, receiver) {
      if(key === "raw") return  target;
      // 如果操作目标是set或者map
      if(isSetMap(target)) {
        if(key === "size")  {
          track(target, ITERATE_KEY)
          return Reflect.get(target, key, target)
        }
        return mutableInstrumentations[key];
      }
      // 如果操作目标是数据, 并key存在arrayInstrumentations上, 那么返回定义在arrayInstrumentations的中
      if(Array.isArray(target) && arrayInstrumentations.hasOwnProperty(key)) {
        // 为什么这里就直接返回, 因为不需要跟踪数组的方法
        return Reflect.get(arrayInstrumentations, key, receiver);
      }
      if(!isReadOnly && typeof key !== "symbol") {
        track(target, key);
      }
      let res = Reflect.get(target, key, receiver);
      if(isShallow) return res;
      if(typeof res === "object" && res !== null) {
        return isReadOnly ? readonly(res) : reactive(res);
      }
      return res;
    },
    
    // 对应obj.key = 11
    set(target, key, newVal, receiver) {
      if(isReadOnly) {
        console.warn(`属性${key}是只读的`);
        return true;
      }
      let oldValue = target[key];
      let type = Array.isArray(target) ? Number(key) < target.length ? "SET" : "ADD" :  Object.prototype.hasOwnProperty.call(target, key) ? "SET": "ADD";
      let res = Reflect.set(target, key, newVal, receiver)
      if(target === receiver.raw){
        if(oldValue !== newVal && (oldValue === oldValue || newVal === newVal)){
          trigger(target, key, type, newVal);
        }
      }
      return res
    },
    
    // 对应delete obj.key
    deleteProperty(target, key) {
      if(isReadOnly) {
        console.warn(`属性${key}是只读的`);
        return true;
      }
      const hadKey = Object.prototype.hasOwnProperty.call(target, key);
      const res =  Reflect.deleteProperty(target, key);
      if(hadKey && res) {
        trigger(target, key, "DELETE");
      }
    },
    
    // 对应key in obj
    has(target, key) {
      track(target, key)
      return Reflect.has(target, key)
    },
    
    // 对应for(ley key in obj)
    ownKeys(target) {
      // const ITERATE_KEY = new Symbol()
      // 因为for...in没有对应的key, 所以通过Symbol来创建唯一的key建立对应的响应关系
      track(target, Array.isArray(target) ? "length" : ITERATE_KEY)
      return Reflect.ownKeys(target)
    }
  });
}
let reactiveMap = new Map();
function reactive(data) {
  let existionProxy = reactiveMap.get(data);
  if(existionProxy) return existionProxy
  let proxy = createReactive(data)
  reactiveMap.set(data, proxy)
  return proxy;
}
function shallowReactive(data) {
  return createReactive(data, true)
}

function readonly(data) {
  return createReactive(data, false, true);
}
function shallowReadonly(data){
  return createReactive(data, true, true)
}