由浅入深,带你用JavaScript实现响应式原理( 二 )

  • construct:监听函数是否使用new操作符调用 。
  • function fn(x, y) {return x + y}const fnProxy = new Proxy(fn, {/*target: 目标函数(fn)thisArg: 指定的this对象 , 也就是被调用时的上下文对象({ name: 'curry' })argumentsList: 被调用时传递的参数列表([1, 2])*/apply: function(target, thisArg, argumentsList) {console.log('fn函数使用apply进行了调用')return target.apply(thisArg, argumentsList)},/*target: 目标函数(fn)argumentsList: 被调用时传递的参数列表newTarget: 最初被调用的构造函数(fnProxy)*/construct: function(target, argumentsList, newTarget) {console.log('fn函数使用new进行了调用')return new target(...argumentsList)}})fnProxy.apply({ name: 'curry' }, [1, 2]) // fn函数使用apply进行了调用new fnProxy() // fn函数使用new进行了调用2.4.Proxy所有的捕获器
    除了上面提到的4种捕获器 , Proxy还给我们提供了其它9种捕获器 , 一共是13个捕获器 , 下面对这13个捕获器进行简单总结 , 下面表格的捕获器分别对应对象上的一些操作方法 。
    捕获器handler
    捕获对象
    get()
    属性读取操作
    set()
    属性设置操作
    has()
    in操作符
    deleteProperty()
    delete操作符
    apply()
    函数调用操作
    construct()
    new操作符
    getPrototypeOf()
    Object.getPrototypeOf()
    setPrototypeOf()
    Object.setPrototypeOf()
    isExtensible()
    Object.isExtensible()
    preventExtensions()
    Object.perventExtensions()
    getOwnPropertyDescriptor()
    Object.getOwnPropertyDescriptor()
    defineProperty()
    Object.defineProperty()
    ownKeys()
    Object.getOwnPropertySymbols()
    Proxy捕获器具体用法可查阅MDN:https://developer.mozilla.org/zh-CN/docs/Web/JAVAScript/Reference/Global_Objects/Proxy
    3.Reflect
    在ES6中 , 还新增了一个API为Reflect , 翻译为反射 , 为一个内置对象 , 一般用于搭配Proxy进行使用 。
    3.1.Reflect有什么作用呢?
    可能会有人疑惑 , 为什么在这里提到Reflect , 它具体有什么作用呢?怎么搭配Proxy进行使用呢?
    • Reflect上提供了很多操作JavaScript对象的方法 , 类似于Object上操作对象的方法;
    • 比如:Reflect.getPrototypeOf()类似于Object.getPrototypeOf() , Reflect.defineProperty()类似于Object.defineProperty();
    • 既然Object已经提供了这些方法 , 为什么还提出Reflect这个API呢?这里涉及到早期ECMA规范问题 , Object本是作为一个构造函数用于创建对象 , 然而却将这么多方法放到Object上 , 本就是不合适的;所以 , ES6为了让Object职责单一化 , 新增了Reflect , 将Object上这些操作对象的方法添加到Reflect上 , 且Reflect不能作为构造函数进行new调用;
    3.2.Reflect的基本使用
    在上述Proxy中 , 操作对象的方法都可以换成对应的Reflect上的方法 , 基本使用如下:
    const obj = {name: 'curry',age: 30}// 创建obj的代理对象const objProxy = new Proxy(obj, {// 获取对象属性值的捕获器get: function(target, key) {console.log(`obj对象的${key}属性被访问啦!`)return Reflect.get(target, key)},// 设置对象属性值的捕获器set: function(target, key, newValue) {console.log(`obj对象的${key}属性被设置啦!`)Reflect.set(target, key, newValue)},// 删除对象属性的捕获器deleteProperty: function(target, key) {console.log(`obj对象的${key}属性被删除啦!`)Reflect.deleteProperty(target, key)}})// 设置:objProxy.name = 'kobe' // obj对象的name属性被设置啦!objProxy.age = 24 // obj对象的age属性被设置啦!// 访问:console.log(objProxy.name) // obj对象的name属性被访问啦!console.log(objProxy.age) // obj对象的age属性被访问啦!// 删除:delete objProxy.name // obj对象的name属性被删除啦!3.3.Reflect上常见的方法
    对比Object , 我们来看一下Reflect上常见的操作对象的方法(静态方法):
    Reflect方法
    类似于
    get(target, propertyKey [, receiver])
    获取对象某个属性值 , target[name]
    set(target, propertyKey, value [, receiver])
    将值分配给属性的函数 , 返回一个boolean
    has(target, propertyKey)
    判断一个对象是否存在某个属性 , 和in运算符功能相同


    推荐阅读