JS学习笔记(八)代理与反射

梦想不抛弃苦心追求的人,只要不停止追求,你们会沐浴在梦想的光辉之中。再美好的梦想与目标,再完美的计划和方案,如果不能尽快在行动中落实,最终只能是纸上谈兵,空想一番。只要瞄准了大方向,坚持不懈地做下去,才能够扫除挡在梦想前面的障碍,实现美好的人生蓝图。JS学习笔记(八)代理与反射,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

JS学习笔记(八)代理与反射

代理和反射为开发者提供了拦截并向基本操作嵌入额外行为的能力。即给目标对象定义一个关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用

一、代理

1.1 创建空代理

       默认情况下,在代理对象上执行的所有操作都会无障碍的传播到目标对象。因此,在任何可以使用目标对象的地方,都可通过同样的方式来使用与之相关联的代理对象。

       代理是使用:Proxy 构造函数创建。 接收两个参数:目标对象和处理程序对象。两者缺一不可

const target = {
    id:'target'
};
const handler = {};
const proxy = new proxy(target,handler);

// id会访问同一个值
console.log(target.id);
console.log(proxy.id);

// 给目标属性赋值会反映到两个对象上,因为两个对象访问的是同一个值
target.id='foo';
console.log(target.id);
console.log(proxy.id);

// 给代理属性赋值会反映到两个对象上,因为这个赋值会转移到目标对象上
proxy.id='bar';
console.log(target.id);
console.log(proxy.id);

//hasOwnProPerty()在两个地方都会引用到目标对象
console.log(target.hasOwnProperty('id'));
console.log(proxy.hasOwnProperty('id'));

//Proxy.prototype是undefined 因此不能用instanceof操作符,会报错

// 严格相等可用来区分代理和目标
console.log(target === proxy); //false

 

1.2 定义捕获器

​       是在处理程序对象中定义的“基本操作的拦截器”。每个处理程序对象可以包含零个或者多个**捕获器,每个捕获器都对应一种基本操作,可以直接或间接在代理对象上调用。每次在代理对象上调用这些基本操作时,代理可以在这些操作传播到目标对象之前先调用捕获器,从而拦截并修改相应的行为。

const target = {
    foo:'bar'
};
const handler = {
    // 捕获器在处理程序对象中以方法名为键
    get() {
        return 'handle override';
    }
};
const proxy = new proxy(target,handler);

console.log(target.foo); // bar
console.log(proxy.foo);	 // handle override

console.log(target['foo']);// bar
console.log(proxy['foo']);// handle override

console.log(Object.create(target)['foo']);// bar
console.log(Object.create(proxy)['foo']);// handle override

 

1.3 捕获器参数和反射API

       所有捕获器都可以访问相应的参数,基于这些参数可以重建被捕获方法的原始行为。如:get()捕获器会接收目标对象要查询的属性代理对象三个参数

      处理程序对象中所有可以捕获的方法都有对应的反射API方法。这些方法与捕获器拦截的方法具有相同的名称和函数签名,且具有与被拦截方法相同的行为。

const target = {
    foo:'bar',
    baz:'qux'
};
const handler = {
    get(trapTarget,property,receiver) {
        let decoration = '';
        if(property === 'foo') {
            decoration = '!!!';
        }
        return Reflect.get(...arguments) + decoration;
    }
};
const proxy = new proxy(target,handler);

console.log(target.foo);//bar
console.log(proxy.foo); //bar!!!

console.log(target.baz);//qux
console.log(proxy.baz); //qux

 

1.4 可撤销代理

       对于使用new proxy()创建的普通代理来说,这种联系会在代理对象的生命周期内一直持续存在。proxy暴露revocable()方法,此方法支持撤销代理对象与目标对象的关联

const target = {
    foo:'bar'
};
const handler = {
    get() {
        return 'intercepted';
    }
};
const {proxy,revoke} = Proxy.revocable(target,handler);

console.log(target.foo); //bar
console.log(proxy.foo);	//'intercepted'

revoke();

console.log(proxy.foo); //TypeError

 

1.5 实用反射API

1.5.1 反射API与对象API

使用反射API需记住:

  • 反射API并不限于捕获处理程序
  • 大多数反射API方法在Object类型上有对应的方法

 

1.5.2 状态标记

很多反射方法返回称作“状态标记”的布尔值,表示意图执行的操作是否成功。

提供状态标记的反射方法:

  • Reflect.defineProperty()
  • Reflect.preventExtensions()
  • Reflect.setPrototypeOf()
  • Reflect.set()
  • Reflect.deleteProperty()

 

1.5.3 用一等函数替代操作符

  • Reflect.get():替代对象属性访问操作符
  • Reflect.set():替代=赋值操作符
  • Reflect.has():替代in操作符或者with()
  • Reflect.deleteProperty():替代delete操作符
  • Reflect.construct():替代new操作符

 

二、代理捕获器与反射方法

2.1 get()

get()捕获器会在获取属性值的操作中被调用。对应的反射API方法为Reflect.get()

1. 返回值

无限制

2. 拦截的操作

  • proxy.property
  • proxy[property]
  • Object.create(proxy)[property]
  • Reflect.get(proxy,property,receiver)

3. 捕获器不变式

若target.property不可写且不可配置,则处理程序返回的值必须与target.property匹配

若target.property不可配置且[[Get]]特性为undefined,处理程序的返回值也必须是undefined。

 

2.2 set()

set()捕获器在设置属性值的操作值中被调用。

1. 返回值

返回true表示成功,false表示失败。严格模式下会报错

2. 拦截的操作

  • proxy.property = value
  • proxy[property] = value
  • Object.create(proxy)[property] = value
  • Reflect.get(proxy,property,value,receiver)

 

2.3 has()

has()捕获器在设in操作符中被调用。

1. 返回值

必须返回布尔值,表示属性是否存在。返回非布尔值会被转型为布尔值

2. 拦截的操作

  • property in proxy
  • property in Object.create(proxy)
  • with(proxy) { (property); }
  • Reflect.has(proxy,property)

 

2.4 defineProperty()

defineProperty()捕获器在Object.defineProperty()中被调用。

1. 返回值

必须返回布尔值,表示属性定义是否存在。返回非布尔值会被转型为布尔值

2. 拦截的操作

  • Object.defineProperty(proxy, property, descriptor)

  • Reflect.defineProperty(proxy, property, descriptor)

3. 参数

descriptor:包括可选的enumerable、configurable、writable、value、get 和 set定义的对象

 

2.5 getOwnPropertyDescriptor()

getOwnPropertyDescriptor()捕获器在getOwnPropertyDescriptor()中被调用。

1. 返回值

必须返回对象,或者在属性不存在时返回undefined

2. 拦截的操作

  • Object.getOwnPropertyDescriptor()(proxy, property)

  • Reflect.getOwnPropertyDescriptor()(proxy, property)

 

2.6 deleteProperty()

deleteProperty()捕获器在delete操作符中被调用。

1. 返回值

必须返回布尔值,表示属性是否删除成功

2. 拦截的操作

  • delete proxy.property

  • delete proxy[property]

  • Reflect.deleteProperty(proxy, property)

 

2.7 ownKeys()

ownKeys()捕获器在Object.keys及类似方法中被调用。

1. 返回值

必须返回包含字符串或符号的可枚举对象

2. 拦截的操作

  • Object.getOwnPropertyNames(proxy)

  • Object.getOwnPropertySymbols(proxy)

  • Object.keys(proxy)

  • Reflect.ownKeys(proxy)

 

2.8 getPrototypeOf()

getPrototypeOf()捕获器在Object.getPrototypeOf()中被调用。

1. 返回值

必须返回对象或null

2. 拦截的操作

  • Object.getPrototypeOf(proxy)

  • Reflect.getPrototypeOf(proxy)

  • proxy.__proto__

  • Object.prototype.isPrototypeOf(proxy)

  • proxy instanceof Object

 

2.9 setPrototypeOf()

setPrototypeOf()捕获器在Object.setPrototypeOf()中被调用。

1. 返回值

必须返回布尔值,表示原型赋值是否成功

2. 拦截的操作

  • Object.setPrototypeOf(proxy)

  • Reflect.setPrototypeOf(proxy)

 

2.10 isExtensible()

isExtensible()捕获器在Object.isExtensible()中被调用。

1. 返回值

必须返回布尔值,表示target是否可扩展

2. 拦截的操作

  • Object. isExtensible(proxy)

  • Reflect. isExtensible(proxy)

 

2.11 preventExtensions()

preventExtensions()捕获器在Object.preventExtensions()中被调用。

1. 返回值

必须返回布尔值,表示target是否已经不可扩展

2. 拦截的操作

  • Object. preventExtensions(proxy)

  • Reflect. preventExtensions(proxy)

 

2.12 apply()

apply()捕获器在调用函数时被调用。

1. 返回值

无限制

2. 拦截的操作

  • proxy(…argumentList)

  • Function.prototype.apply(thisArg,arguementsList)

  • Function.prototype.call(thisArg,…argumentsList)

  • Reflect. apply(target,thisArgument,argumentsList)

 

2.13 construct()

construct()捕获器在new操作符中被调用。

1. 返回值

construct()必须返回一个对象

2. 拦截的操作

  • new proxy(…argumentsList)

  • Reflect. construct(target, argumentsList, newTarget)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/150432.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!