深入浅出JS—15 ES6中Proxy及Reflect的使用

深入浅出JS—15 ES6中Proxy及Reflect的使用,第1张

在一些前端框架中,常常需要监听数据变化,页面进行响应。为了监听对象的变化,需要对对象的 *** 作进行捕获。本文着重介绍ES6中Proxy代理对象的使用,以及涉及到的映射对象Reflect使用

1. Proxy的设计初衷

为了监听对象的属性 *** 作,在ES6之前一般借助于Object.defineProperty来实现,但有以下缺点

Object.defineProperty设计初衷并不是要监听属性对于新增属性、删除属性监听不到将原来对象修改了(数据属性描述符–》存取属性描述符),不应该改变原始对象

在ES6中,新增了一个Proxy类,Proxy翻译为“代理”,是用于帮助我们创建一个代理的:

如果我们希望监听一个对象的相关 *** 作,那么我们可以先创建一个代理对象(Proxy对象)之后对该对象的所有 *** 作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些 *** 作 2. Proxy类用法

const objProxy = new Proxy(obj, handler);
其中参数obj是要代理的原始对象,handler是捕获器对象,包含13中捕获器方法

// 1 原始对象
const obj = { name: "xs", age: 18 };
console.log(obj);

// 2 代理对象
// new Proxy(target, handler)第一个参数为要代理的目标对象,第二个为对对象 *** 作的监听处理对象
const objProxy = new Proxy(obj, {}); 
console.log(objProxy);

浏览器中打印如下:可以清楚看到第一个是对象类型Object,第二个是Proxy类型对象

3. Proxy捕获器

那么,代理对象如何监听我们的 *** 作呢,就需要用到捕获器,Proxy中有13种捕获器

4种常用捕获器(熟练)

创建Proxy对象的第二个入参为handler对象,里面可以设置13中捕获器方法,但最常用的只有4种:get
set, has, deleteProperty

const obj = {
  name: "xs",
  age: 18,
};

const objProxy = new Proxy(obj, {
  // 获取值 捕获器 target:obj,
  get(target, key) {
    console.log(`监听到对象的${key}属性被访问了`, target);
    return target[key];
  },

  // 设置值 捕获器
  set(target, key, newValue) {
    console.log(`监听到对象的${key}属性被赋值了`, target);
    target[key] = newValue;
  },
  
  // has 捕获器
  has(target, key) {
    console.log(`监听到对象的${key}属性in *** 作`, target);
    target.has(key)
  },

 // delete 捕获器
  deleteProperty(target, key) {
    console.log(`监听到对象的${key}属性删除 *** 作`, target);
    delete target[key];
  },
});

调用

console.log(objProxy.name); // get
objProxy.name = 'kobe'; // set
console.log('name' in obj) // has
delete obj.name // deleteProperty
2种与函数相关的捕获器(了解) apply 捕获函数的apply方法construct 捕获函数作为构造函数
// 1 创建函数对象
function foo() {
  console.log(this);
}

// 2 创建函数代理对象
const fooProxy = new Proxy(foo, {
  // 设置apply捕获器
  apply(target, thisArg, argArray) {
    console.log(`监听函数${target.name}的apply *** 作`);
    target.apply(thisArg, argArray);
  },
 
  // 设置构造函数捕获器 
  construct(target, argArray) {
    console.log(`监听函数${target.name}的construct *** 作`);
    return new target(...argArray);
  }
});

// 3 调用代理对象
fooProxy(); // 不会被捕获
fooProxy.apply({ name: "xs" }, ["dsh", "dshjk"]); // 监听函数foo的apply *** 作
const f = new fooProxy(); // 监听函数foo的construct *** 作

4. Reflect映射对象

Reflect也是ES6中提出的一个新对象,字面意思是反射。(看着高大上,其实很简单)
简单认知:Reflect是Object的一个替身。Object.getOwnProperty()和Reflect.getOwnProperty()一样

Reflect的作用 如果我们有Object可以做这些 *** 作,那么为什么还需要有Reflect这样的新增对象呢? 因为在早期的ECMA规范中没有考虑到这种对 对象本身 的 *** 作如何设计会更加规范,所以将这些API放到了Object上面,但是Object作为一个构造函数,这些 *** 作实际上放到它身上并不合适另外还包含一些类似于 in、delete *** 作符,让JS看起来是会有一些奇怪的所以在ES6中新增了Reflect,让我们这些 *** 作都集中到了Reflect对象上 Reflect的方法

Reflect中有13种方法,与Proxy一一对应


5. Proxy + Reflect配合使用

用Reflect替换代理对象捕获器中直接对原对象进行 *** 作

const obj = {
  name: "xs",
  age: 18,
};

const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    // receiver永远指向 Proxy 本身或者继承它的对象
    return Reflect.get(target, key, receiver); // 语言内部获取,替代return target[key]
    // Reflect中的receiver可以改变计算属性中 this 的指向
  },

  set(target, key, newValue, receiver) {
    Reflect.set(target, key, newValue, receiver); //会返回一个布尔值,标志 *** 作是否成功 替代target[key] = newValue
  },
});

objProxy.name = "kobe";
console.log(objProxy.name);
6. 总结

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940680.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存