学习Vue3必须了解的ES6语法——Proxy

1. Proxy

关联知识:defineproperty

作用:代理器

本质:重载了对象的点运算符(相当在语言层面做出了修改)

应用场景:vue3的响应式数据采用的就是Proxy对象,vue2则是通过defineproperty进行数据代理。两者作用一致,Proxy相当于是defineProperty在数据代理上的优化,属于ES6语法。

前提:必须为Object类型(即对象类型),Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写

const proxy = new Proxy({},{
  get: function(target,propKey,receiver){
     console.log('get')
     return Reflect.get(target, propKey, receiver);
  },
  set: function(target,propKey,value,receiver){
    console.log('get')
    return Reflect.set(target, propKey, value, receiver);
	}
})

proxy.a = 'hello proxy!' // set
console.log(proxy.a) // get 
//  hello proxy!

Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象上的方法,就能在Reflect对象上找到对应的方法。这就使Proxy对象可以方便地调用对应Reflect的方法来完成默认行为,作为修改的基础。无论Proxy怎么修改默认行为,我们总能在Reflect上获取默认行为。

Reflect是ES6为了操作对象而提供新的API

(1) ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。

const proxy = new Proxy(target, handler);

Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

  • 如果handler是一个空对象,则proxy实例相当于普通对象

proxy一共支持13种拦截操作 来源:

ES6 入门教程

  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

(2)get操作的使用例子

  • 使用get拦截,实现数组读取负数的索引。
function createArray(...elements){
  let handler = {
    get(target,propKey,receiver){
      let index = Number(propKey);
      if(index < 0){
        propKey = String(target.length + index)
      }
      return Reflect.get(target,propKey,receiver)
    }
  }
  let target = [...elements]
  return new Proxy(target,handler)
}
let arr = createArray('a', 'b', 'c');
arr[-1] // c
  • 利用 Proxy,可以将读取属性的操作(get),转变为执行某个函数,从而实现属性的链式操作。

这个例子稍微有点复杂,关于链式操作的一些细节还需要深入了解

简单的了解一下链式操作 javascript中的链式操作 - 知乎

const pipe = function (value) {
  var funcStack = [];
  var oproxy = new Proxy({} , {
    get : function (pipeObject, fnName) {
      if (fnName === 'get') {
        return funcStack.reduce(function (val, fn) {
          return fn(val);
        },value);
      }
      funcStack.push(window[fnName]);
      return oproxy;
    }
  });

  return oproxy;
}

var double = n => n * 2;
var pow    = n => n * n;
var reverseInt = n => n.toString().split("").reverse().join("") | 0;

pipe(3).double.pow.reverseInt.get; // 63

上面例子通过函数传递初始值返回Proxy对象,相当于pip函数进行了劫持,并利用闭包思想对每次的点操作符的属性进行监听,当监听到属性值不为'get'时,将当前函数push到外层的funcStack数组,直到propKey为'get'时开始通过reduce函数遍历执行funcStack中的函数。

 

这里只列出了get操作的例子 ,所有拦截操作的例子->Proxy - ECMAScript 6入门 (ruanyifeng.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值