ES6知识点:Proxy和Reflect详解

Posted 还是不会呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6知识点:Proxy和Reflect详解相关的知识,希望对你有一定的参考价值。

ES6新增一个代理类:Proxy。监听一个对象的相关操作,可以创建一个对应的代理对象,对原对象的操作通过代理对象来完成。

ES6新增一个对象:Reflect(反射),用来替换Object内的一些方法。

Proxy的基本使用

修改代理对象,原对象会发生对应改变

const info = { name: "fzb", age: 21 };

const proxy = new Proxy(info, {});
proxy.name = "zkl";
proxy.age = 22;

// 修改代理对象,原对象也会发生对应改变
console.log(info); // { name: 'zkl', age: 22 }

Proxy的十三种捕获器

最常用的是前面四种捕获器

set和get捕获器

对对象的取值和设置进行拦截

const info = { name: "fzb", age: 21 };

//为info对象创建
const proxy = new Proxy(info, {
  // target:原对象, key:操作的key, receiver: 创建的代理对象
  get: function (target, key, receiver) {
    console.log(`拦截到正在获取${key}`, target);
    return target[key];
  },
  // newValue: 设置值的新值
  set: function (target, key, newValue, receiver) {
    console.log(`拦截到正在设值的${key}`, target);
    target[key] = newValue;
  },
});

console.log(proxy.name);
proxy.age = 22;
// 控制台打印:
// 拦截到正在获取name { name: 'fzb', age: 21 }
// fzb
// 拦截到正在设值的age { name: 'fzb', age: 21 }

has捕获器

in操作进行拦截

const info = { name: "fzb" };
const proxy = new Proxy(info, {
  has: function (target, key) {
    console.log(`拦截到in操作符,属性是:${key}`);
    return key in target;
  },
});

console.log("name" in proxy); // true
// 控制台打印:
// 拦截到in操作符,属性是:name
// true

deleteProperty捕获器

对属性的删除(delete关键字)进行拦截

const info = { name: "fzb" };
const proxy = new Proxy(info, {
  deleteProperty: function (target, key) {
    console.log(`拦截到key值为${key}的删除操作`);
    delete target[key];
  },
});

delete proxy.name; // 拦截到key值为name的删除操作
console.log(proxy); // {}

getPrototypeOf捕获器

对获取对象的原型(Object.getPrototypeOf)时进行拦截

const info = {};
const proxy = new Proxy(info, {
  getPrototypeOf: function (target) {
    console.log(`拦截到了获取原型的过程`);
    return Object.getPrototypeOf(target);
  },
});
console.log(Object.getPrototypeOf(proxy));
// 浏览器打印:
// 拦截到了设置原型的过程
// [Object: null prototype] {}

setPrototypeOf捕获器

在设置对象原型(Object.setPrototypeOf)时进行拦截

const info = {};
const proxy = new Proxy(info, {
  setPrototypeOf: function (target, object) {
    console.log(`拦截到了设置原型的过程`);
    return Object.setPrototypeOf(target, object);
  },
});
Object.setPrototypeOf(proxy, {}); // 拦截到了设置原型的过程
console.log(proxy.__proto__); // {}

isExtensible捕获器

在对象进行扩展属性(Object.isExtensible)时进行拦截

const info = {};
const proxy = new Proxy(info, {
  isExtensible: function (target) {
    console.log(`拦截到了对象允许进行扩展新的属性`);
    return Object.isExtensible(target);
  },
});

console.log(Object.isExtensible(proxy));
// 浏览器打印:
// 拦截到了对象允许进行扩展新的属性
// true

preventExtensions捕获器

在对象不准进行扩展属性(Object. preventExtensions)时进行拦截

const info = {};
const proxy = new Proxy(info, {
  preventExtensions: function (target) {
    console.log(`拦截到了对象不允许进行扩展新的属性`);
    return Object.preventExtensions(target);
  },
});

console.log(Object.preventExtensions(proxy));
// 浏览器打印:
// 拦截到了对象不允许进行扩展新的属性
// {}

getOwnPropertyDescriptor捕获器

在获取对象的某个key值得属性描述符(Object.getOwnPropertyDescriptor)时进行拦截

const info = { name: "fzb" };
const proxy = new Proxy(info, {
  getOwnPropertyDescriptor: function (target, key) {
    console.log(`拦截到获取key值为${key}的描述器的过程`);
    return Object.getOwnPropertyDescriptor(target, key);
  },
});

console.log(Object.getOwnPropertyDescriptor(proxy, "name"));
// 浏览器打印:
// 拦截到获取key值为name的描述器的过程
// { value: 'fzb', writable: true, enumerable: true, configurable: true }

defineProperty捕获器

在设置对象得属性描述符(Object.defineProperty)时进行拦截

const info = { name: "fzb" };
const proxy = new Proxy(info, {
  defineProperty: function (target, key, attributes) {
    console.log(`拦截到为key值为${key}的设置描述器的过程`);
    return Object.defineProperty(target, key, attributes);
  },
});

console.log( Object.defineProperty(proxy, "age", {
    configurable: true,
    writable: true,
    enumerable: true,
    value: 21, 
   })
);
// 浏览器打印:
// 拦截到为key值为age的设置描述器的过程
// { name: 'fzb', age: 21 }

apply捕获器

函数在进行apply调用时进行拦截

function foo(...args) {
  console.log(this, args);
}

const proxy = new Proxy(foo, {
  apply: function (target, thisArg, argArray) {
    console.log(`拦截到函数apply执行方式的过程`);
    return target.apply(thisArg, argArray);
  },
});
proxy.apply("fzb", [1, 2, 3, 4]);
// 浏览器打印:
// 拦截到函数apply执行方式的过程
// [String: 'fzb'] [ 1, 2, 3, 4 ]

construct捕获器

函数通过new关键字调用时拦截

function Person() {}

const proxy = new Proxy(Person, {
  // newTarget在Reflect时的用法
  construct: function (target, argArray, newTarget) {
    console.log(`函数进行了new调用`);
    return new target(...argArray);
  },
});
new proxy(); // 函数进行了new调用

ownKeys捕获器

在获取对象的key(Object.getOwnPropertyNamesObject.getOwnPropertySymbols)值时进行拦截

Reflect的基本使用

Reflect的常用方法

包含了类似indelete操作符的一些方法

比较 Reflect 和 Object 方法

Reflect和Proxy一起使用

在上方Proxy的十三种捕获器内的操作,其实还是直接在原对象上操作

const info = {};

const proxy = new Proxy(info, {
  set(target, kry, newValue, receiver) {
    return Reflect.set(target, kry, newValue, receiver);
  },
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver);
  },
  has(target, key) {
    return Reflect.has(target, key);
  },
  deleteProperty(target, key) {
    return Reflect.deleteProperty(target, key);
  },
  setPrototypeOf(target, object) {
    return Reflect.setPrototypeOf(target, object);
  },
  getPrototypeOf(target) {
    return Reflect.getPrototypeOf(target);
  },
  getOwnPropertyDescriptor(target, key) {
    return Reflect.getOwnPropertyDescriptor(target, key);
  },
  isExtensible(target) {
    return Reflect.isExtensible(target);
  },
  preventExtensions(target) {
    return Reflect.preventExtensions(target);
  },
  ownKeys(target) {
    return Reflect.ownKeys(target);
  },
  apply(target, thisArg, argArray) {
    return Reflect.apply(target, thisArg, argArray);
  },
  construct(target, argArray, newTarget) {
    return Reflect.construct(target, argArray, newTarget);
  },
});

对于Reflect.ownKeys还是只能得到key不为Symbol

Reflect.receiver的作用

只有setget存在receiver

const info = {
  _name: "fzb",
  set name(newValue) {
    this._name = newValue;
  },
  get name() {
    return this._name;
  },
};
const proxy = new Proxy(info, {
  //   get: function (target, key, receiver) {
  //     console.log("-------");
  //     return Reflect.get(target, key);
  //   },
  //   set: function (target, key, newValue, receiver) {
  //     return Reflect.set(target, key, newValue);
  //   },
  get: function (target, key, receiver) {
    console.log("-------");
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, newValue, receiver) {
    return Reflect.set(target, key, newValue, receiver);
  },
});

console.log(proxy.name);
// "-------" /n "fzb"
// 解析: 取到的值是正确的,获取name时确实是通过proxy,但是分割线只打印了一次
// 在name访问器获取或设置_name的时候,这时的this已经是info
// receiver就是创建的代理对象,Reflect传入receiver会将内部的this改为代理对象

// proxy内代码注释,并且传入receiver后打印:
// -------
// -------
// fzb

Reflect.construct的使用

function Person() {}

function Student() {}

const stu1 = new Student();
console.log(stu1.__proto__ === Student.prototype); // true

const stu2 = Reflect.construct(Person, [], Student);
// 通过Person创建出来的对象,但是类型却是:Student类型
console.log(stu2.__proto__ === Student.prototype); // true

以上是关于ES6知识点:Proxy和Reflect详解的主要内容,如果未能解决你的问题,请参考以下文章

利用ES6中的Proxy和Reflect 实现简单的双向数据绑定

ES6(Proxy 和 Reflect)

es6——Proxy和Reflect

ES6 Proxy和Reflect

ES6初识-Proxy和Reflect

ES6-Proxy and Reflect