资讯专栏INFORMATION COLUMN

初识Proxy、Reflect

gougoujiang / 2912人阅读

摘要:主要原因应该是在处理数组响应是会存在缺陷。构造函数其中表示生成一个实例,为需要代理的对象,则是一个对象,定义了各种代理行为。对于满足条件的属性以及其他属性,直接保存报错报错拦截的操作,返回一个布尔值。

前言
https://segmentfault.com/a/11...

Vue3.0应该马上就要发布正式版了。听说在新版本中,Proxy取代了Object.defineProperty进行双向绑定。主要原因应该是Object.defineProperty在处理数组响应是会存在缺陷。

let demo = {};
let arr = [];

Object.defineProperty(demo, "arr", {
  get: function() {
    return arr;
  },
  set: a => {
    console.log("hear set");
    arr = a;
  },
  configurable: true,
  enumerable: true
});

demo.arr = [1, 2, 3, 4]; // => "hear set";
console.log(arr === demo.arr); // => true
/* 通过索引修改数组,无法触发set */
demo.arr[2] = null; // => 没有输出hear set。
console.log(arr === demo.arr); // => true
/* 通过push,pop,sort等方法同样无法触发set */
demo.arr.push("13"); // => 没有输出hear set。

Proxy
http://es6.ruanyifeng.com/#do...
示例

Proxy原意为代理,在实际操作中,可以理解为,在目标数据前增加一个拦截器。通过拦截器,可以实现监听、修改目标数据。

let obj = new Proxy(
  {},
  {
    set: function(target, key, receiver) {
      console.log(`set key ${key}`);
      return Reflect.set(target, key, receiver);
    },
    get: function(target, key, receiver) {
      console.log(`get key ${key}`);
      return Reflect.get(target, key, receiver);
    }
  }
);

obj.count = 1;
// => set key count;
obj.count++;
// => get key count;
// => set key count;

构造函数
let obj = new Proxy(target, handler)

其中new Proxy表示生成一个Proxy实例,target为需要代理的对象,handler则是一个对象,定义了各种代理行为。
如果handler为空对象,访问proxy与访问target效果相同。

Proxy的实例方法 get()

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

var person = {
  name: "张三"
};

var proxy = new Proxy(person, {
  get: function(target, property) {
    if (property in target) {
      return target[property];
    } else {
      throw new ReferenceError("Property "" + property + "" does not exist.");
    }
  }
});

proxy.name // "张三"
proxy.age // 抛出一个错误
set()

set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

let validator = {
  set: function(obj, prop, value) {
    if (prop === "age") {
      if (!Number.isInteger(value)) {
        throw new TypeError("The age is not an integer");
      }
      if (value > 200) {
        throw new RangeError("The age seems invalid");
      }
    }

    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = "young" // 报错
person.age = 300 // 报错
has()

has(target, propKey)拦截propKey in proxy的操作,返回一个布尔值。

deleteProperty()

deleteProperty(target, propKey)拦截delete proxy[propKey]的操作,返回一个布尔值。

ownKeys()

ownKeys(target)拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。

getOwnPropertyDescriptor()

getOwnPropertyDescriptor(target, propKey)拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。

defineProperty()

defineProperty(target, propKey, propDesc)拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。

preventExtensions()

preventExtensions(target)拦截Object.preventExtensions(proxy),返回一个布尔值。

getPrototypeOf()

getPrototypeOf(target)拦截Object.getPrototypeOf(proxy),返回一个对象。

isExtensible()

isExtensible(target)拦截Object.isExtensible(proxy),返回一个布尔值。

setPrototypeOf()

setPrototypeOf(target, proto)拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。

apply()

apply(target, object, args)拦截Proxy实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)、proxy.apply(...)

construct()

construct(target, args)拦截Proxy实例作为构造函数调用的操作,比如new proxy(...args)

Reflect
http://es6.ruanyifeng.com/#do...
简介

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。其目的是:

Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。

修改某些Object方法的返回结果,让其变得更合理。

Object操作都变成函数行为。

Reflect对象的方法与Proxy对象的方法一一对应

使用Proxy监听数组
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, { set });
function set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    queuedObservers.forEach(observer => observer());
    return result;
}
const person = observable({
    name: "Amber",
    age: 18
});
function print() {
    console.log(`${person.name}, ${person.age}`);
}
observe(print);

使用Proxy、Reflect实现观察者模式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100820.html

相关文章

  • ECMAScript6(12):ProxyReflect

    摘要:返回一个布尔值拦截操作符,返回一个布尔值拦截操作符,返回一个布尔值拦截遍历器,返回一个遍历器拦截,返回一个布尔值拦截,返回一个数组。 Proxy 对象 Proxy 用来修改某些默认操作,等同于在语言层面做出修改。所以属于一种元编程(meta programming), 即对编程语言进行编程。字面理解为Proxy代理了某些默认的操作。其使用格式如下: var proxy = new Pr...

    habren 评论0 收藏0
  • ES6之Reflect

    摘要:查找并返回对象的属性例例属性部署了读取函数返回的是的参数对象注意如果的第一个参数不是对象,则会报错。它返回一个布尔值,表示是否操作成功用于返回对象的所有属性使用和实现观察者模式请参考观察者模式 1、什么是Reflect?为操作对象而提供的新API 2、为什么要设计Reflect?(1)将Object对象的属于语言内部的方法放到Reflect对象上,即从Reflect对象上拿Object...

    BingqiChen 评论0 收藏0
  • ES6 中的 ReflectProxy

    摘要:是中新增的特性。首先来说,的提出是为了整合之前中存在的一些不太合理的地方。表示当前对象是否可扩展,返回一个布尔值。更完美的枚举很多代码使用字符串普通或冻结的对象作为枚举。通过记录这些访问和修改信息,能记录下对这个对象的所有操作记录。 Reflect Reflect 是ES6中新增的特性。它是一个普通对象,下面有13个静态方法(enumerate在最终的发布版中被移除),可以再全局下访问...

    wzyplus 评论0 收藏0
  • ECMAScript 6入门ProxyReflect(上)

    摘要:与学习的新语法糖既能学习到新东西,又能使得自己的代码更加优雅,逼格更高,爽与之间的运用就是对对象的操作触发的拦截是对对象进行代理,通过生成的对象间接操作原本对象,最常见的就是与语法形式是需要操作的对象,而是包含操作对象的一些方法的对象是能够 Proxy与Reflect 学习es6的新语法糖既能学习到新东西,又能使得自己的代码更加优雅,逼格更高,爽proxy与Reflect之间的运用就是...

    DevTTL 评论0 收藏0
  • 深入理解ES6之《代理和反射》

    摘要:使用陷阱验证属性用于接收属性代理的目标的对象要写入的属性键被写入的属性的值操作发生的对象通常是代理属性必须是数字抛错用陷阱验证对象结构属性不存在抛出错误使用陷阱隐藏已有属性可以用操作符来检测给定对象中是否包含有某个属性,如果自有属性或原型属 使用set陷阱验证属性 let target = { name: target } let proxy = new Proxy(targe...

    Stardustsky 评论0 收藏0

发表评论

0条评论

gougoujiang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<