ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaScript简餐——代理Proxy与反射(一)

2021-11-06 23:01:55  阅读:144  来源: 互联网

标签:const name 对象 捕获 JavaScript person 简餐 Proxy proxy


文章目录


前言

写本《JavaScript简餐》系列文章的目的是记录在阅读学习《JavaScript高级程序设计(第4版)》一书时出现的各个知识点。虽是对读书的笔记和总结,但是希望它轻量、简洁、犀利,不会引起阅读疲劳,可以在碎片化时间和闲暇之余轻巧地沐浴一下知识点。每篇文章只针对一个小部分进行讲解式的梳理,来达到个人复习总结和分享知识的目的。


ECMAScript6中新增了代理与反射,让我们可以给目标对象定义一个关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。

一、代理Proxy基础

代理是目标对象的抽象。从很多方面看,代理类似C++中的指针,因为它可以用作目标对象的替身,但又完全独立于目标对象。目标对象既可以直接被操作,也可以通过代理来操作。说句人话:代理就是对象的分身,在分身上的所有操作都会影响到“本体”。要创建代理,最简单的就是创建空代理,即除了作为一个对象的抽象什么也不做。代理是使用Proxy构造函数创建的。这个构造函数接收两个参数:目标对象和处理程序对象,二者缺一不可。话不多说直接上代码:
const person = {
    name: 'Lucy'
};

const handler = {};

const proxy = new Proxy(person, handler); // (目标对象, 处理程序对象)

console.log(person.name); // Lucy
console.log(proxy.name); // Lucy

person.name = 'Jack'; // 改变person对象(目标对象)上的name属性那么在proxy上也会改变
console.log(person.name); // Jack
console.log(proxy.name); // Jack

console.log(person === proxy) // false

二、定义捕获器

使用代理的主要目的是可以定义捕获器。捕获器就是在处理程序对象中定义的“基本操作的拦截器”。每个处理程序对象可以包含零个或多个捕获器,每个捕获器都对应一种基本操作,可以直接或间接在代理对象上调用。每次在代理对象上调用这些基本操作时,代理可以在这些操作传播到目标对象之前先调用捕获器函数,从而拦截并修改相应的行为。还是直接上代码来直观理解一下。这里我们在刚刚例子中的handler对象中定义一个get()捕获器。
const person = {
    name: 'Lucy'
};

const handler = {
    get() {
        return '捕获器触发!'
    }
};

const proxy = new Proxy(person, handler); // (目标对象, 处理程序对象)
这样,当通过代理对象执行get()操作时,就会触发定义的get()捕获器。所有这些操作只要发生在代理对象上,就会触发get()捕获器。注意,只有在代理对象上执行这些操作才会触发捕获器。在目标对象执行这些操作仍然会产生正常的行为。我们做一下试验:
console.log(person.name); // Lucy
console.log(proxy.name); // 捕获器触发!
果不其然,在代理对象上执行get操作时捕获器触发了!

三、捕获器参数和反射API

所有捕获器都可以访问相应的参数,基于这些参数可以重建被捕获方法的原始行为。比如,get()捕获器会接收到目标对象、要查询的属性和代理对象这三个参数:
const person = {
    name: 'Lucy'
};

const handler = {
    get(trapTarget, property, receiver) {
        console.log(trapTarget === person);
        console.log(property);
        console.log(receiver === proxy);
    }
};

const proxy = new Proxy(person, handler); // (目标对象, 处理程序对象)

proxy.name;
// true
// name
// true
有了这些参数,就可以重建被捕获方法的原始行为:
const person = {
    name: 'Lucy'
};

const handler = {
    get(trapTarget, property, receiver) {
        return trapTarget[property];
    }
};

const proxy = new Proxy(person, handler); // (目标对象, 处理程序对象)

console.log(person.name); // Lucy
console.log(proxy.name); // Lucy
虽然我们可以自己手动重建原始行为,但是完全可以没这个必要,因为比get复杂的操作还有很多。为此,我们可以通过调用全局Reflect对象上的同名方法来轻松重建。处理程序对象中所有可以捕获的方法都有对应的反射API方法。这些方法与捕获器拦截的方法具有相同的名称和函数签名,而且也具有与被拦截方法相同的行为。因此,使用反射API也可以像下面这样定义出空代理对象:
const person = {
    name: 'Lucy'
};

const handler = {
    get() {
        return Reflect.get(...arguments);
    }
};

const proxy = new Proxy(person, handler); // (目标对象, 处理程序对象)

console.log(person.name); // Lucy
console.log(proxy.name); // Lucy
如果真的想创建一个可以捕获所有方法,然后将每个方法转发给对应反射API的空代理,那么甚至不需要定义处理程序对象:
const person = {
    name: 'Lucy'
};

const proxy = new Proxy(person, Reflect); // (目标对象, 处理程序对象)

console.log(person.name); // Lucy
console.log(proxy.name); // Lucy

四、捕获器不变式

使用捕获器几乎可以改变所有基本方法的行为,但也不是没有限制的。根据ECMAScript规范,每个捕获的方法都知道目标对象上下文、捕获函数签名,而捕获处理程序的行为必须遵守“捕获器不变式”,这个规则通常会防止捕获器定义中出现过于反常的行为。比如,如果目标对象有一个不可配置且不可写的属性,那么在捕获器返回一个与该属性不同的值时会抛出TypeError。代码如下:
const person = {};
Object.defineProperty(person, 'name', {
    configurable: false,
    writable: false,
    value: 'Lucy'
});

const handler = {
    get() {
        return 'Jack';
    }
};

const proxy = new Proxy(person, handler);

console.log(proxy.name); // TypeError: 'get' on proxy: property 'name' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected 'Lucy' but got 'Jack')

五、总结

以上就是今天要讲的内容,今天简单地介绍了一下proxy基础、代理的创建方式、捕获器的定义、捕获器的作用及其用法、反射API和捕获器不变式。下一篇我们来继续深入一下代理Proxy与反射。撒花~

标签:const,name,对象,捕获,JavaScript,person,简餐,Proxy,proxy
来源: https://blog.csdn.net/igodmeetu/article/details/121185274

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有