ES6 中的 Proxy 对象是一种可以在对象访问中拦截、更改或扩展行为的工具。通过 Proxy 对象,我们可以更加灵活地处理对象的属性访问、方法调用、构造器调用等操作。本文将详细介绍 Proxy 对象的使用方法和特性,并给出相关示例代码。
Proxy 对象的基本用法
创建一个 Proxy 对象,需要定义一个 Target 对象和一个 Handler 对象,其中 Target 对象为被代理的对象,Handler 对象为拦截器,用于拦截、处理 Target 对象的各种操作。以下为创建 Proxy 对象的代码示例:
-- -------------------- ---- ------- --- ------ - - ----- ------- ---- -- -- --- ------- - - ---- -------- ----- --------- -- - -------------------- ---------- ------ ------------- -- ---- -------- ----- ------ --------- -- - -------------------- ------- -- ----------- ------------ - ------ ------ ----- - -- --- ----- - --- ------------- ---------
在以上代码中,我们定义了一个 Target 对象 target
,包含 name
和 age
两个属性。同时,我们定义了一个 Handler 对象 handler
,其包含了两个拦截器:get
拦截器用于处理属性访问操作,set
拦截器用于处理属性设置操作。最后,我们使用 new Proxy()
方法创建了 Proxy 对象 proxy
。
通过以上代码,我们可以在 proxy
对象上进行属性的访问和设置,同时拦截器可以捕捉到相关操作并做出相应的处理。
例如,我们可以使用以下代码访问 proxy
对象中的 name
属性:
console.log(proxy.name);
执行以上代码,会先输出 "Getting name"
,表示访问了 name
属性,然后输出 "Lucy"
,表示返回了 target.name
属性的值。相应地,我们也可以使用以下代码来设置 proxy
对象的 name
属性:
proxy.name = 'Lily';
执行以上代码,会先输出 "Setting name to Lily"
,表示设置了 name
属性的值为 "Lily"
。
Proxy 对象的拦截器类型
除了 get
和 set
拦截器,我们还可以使用 Proxy 对象提供的其他拦截器,包括:apply
、construct
、deleteProperty
、has
、getOwnPropertyDescriptor
、defineProperty
、getPrototypeOf
、setPrototypeOf
、isExtensible
、preventExtensions
、ownKeys
等。以下是拦截器的介绍和使用方法:
apply 拦截器
apply
拦截器用于拦截函数调用,比如 func(...args)
或 func.apply(receiver, args)
。其接收三个参数:
- target:被代理的函数;
- thisArg:函数调用时的 this 值;
- argArray:函数调用时传入的参数数组。
以下是一个 apply
拦截器的代码示例:
-- -------------------- ---- ------- --- ---- - --------- -- - -------------------- ---- ---- ------- ------ ------ ----------------- -- -- --- - -- --- -- --- ------- - - ------ -------- -------- --------- -- - -------------------- -------- ---- ------- ---------- ------ -------------------- - -- --- ----- - --- ----------- --------- -------------------- -- -- -- ---- -- -- --
在以上代码中,我们定义了一个函数 func
,接收多个参数并返回它们的和。我们还定义了一个 apply
拦截器,拦截了 proxy
对象的函数调用,输出传入的参数并调用 target(...argArray)
方法。
construct 拦截器
construct
拦截器用于拦截构造函数的调用,例如 new func(...args)
。其接收两个参数:
- target:被代理的构造函数;
- argArray:构造函数调用时传入的参数数组。
以下是一个 construct
拦截器的代码示例:
-- -------------------- ---- ------- ----- ------ - ----------------- ---- - --------- - ----- -------- - ---- - ---------- - ------------------- -- ---- -- ------------- --- ----------- ----- ------- - - --- ------- - - ---------- -------- --------- -- - --- ------ ---- - --------- --------------------- --- ------ ---- ---- ------- --- --- ---------- ------ --- ------------ ----- - -- --- ----- - --- ------------- --------- --- ------ - --- ------------- ---- ------------------ -- -- ------- -- ---- -- ----- --- -- ----- -----
在以上代码中,我们定义了一个 Person
类,包含 name
、age
两个属性,和 sayHello()
方法。我们还定义了一个 construct
拦截器,拦截了 proxy
对象的构造调用,输出传入的参数并调用 target(...argArray)
方法。
deleteProperty 拦截器
deleteProperty
拦截器用于拦截删除一个属性的操作,例如 delete obj.prop
。其接收两个参数:
- target:被代理的对象;
- prop:要删除的属性名。
以下是一个 deleteProperty
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - --------------- -------- ----- -- - --------------------- -------- ---------- ------ ------------- ------ ----- - -- --- ----- - --- ---------- --------- ------ ---------- -- -- --------- -------- ---- ------------------- -- -- ------ -------
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 deleteProperty
拦截器,拦截了 proxy
对象的删除属性操作,输出被删除的属性名并调用 delete target[prop]
方法。
has 拦截器
has
拦截器用于拦截属性是否存在的操作,例如 'prop' in obj
。其接收两个参数:
- target:被代理的对象;
- prop:属性名。
以下是一个 has
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - ---- -------- ----- -- - --------------------- -- -------- ------- --------- ------ ---- -- ------- - -- --- ----- - --- ---------- --------- ------------------ -- ------- -- -- --------- -- -------- ---- ----------- ---- -------------------- -- ------- -- -- --------- -- -------- ------ ----------- -----
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 has
拦截器,拦截了 proxy
对象的检查属性是否存在的操作,输出被检查的属性名并调用 prop in target
方法。
getOwnPropertyDescriptor 拦截器
getOwnPropertyDescriptor
拦截器用于拦截获取属性描述符的操作,例如 Object.getOwnPropertyDescriptor(obj, 'prop')
。其接收两个参数:
- target:被代理的对象;
- prop:属性名。
以下是一个 getOwnPropertyDescriptor
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - ------------------------- -------- ----- -- - -------------------- -------- ---------- -- ---------- ------ --------------------------------------- ------ - -- --- ----- - --- ---------- --------- -------------------------------------------------- --------- -- -- -------- -------- ---------- -- --------- ------- ------- --------- ----- ----------- ----- ------------- -----
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 getOwnPropertyDescriptor
拦截器,拦截了 proxy
对象的获取属性描述符的操作,输出被获取的属性名并调用 Object.getOwnPropertyDescriptor(target, prop)
方法。
defineProperty 拦截器
defineProperty
拦截器用于拦截定义一个属性的操作,例如 Object.defineProperty(obj, 'prop', {value: 123})
。其接收三个参数:
- target:被代理的对象;
- prop:要定义的属性名;
- desc:要定义的属性描述符对象。
以下是一个 defineProperty
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - --------------- -------- ----- ----- -- - --------------------- -------- ------- ---- ------------- ------ ------ ----------------------------- ----- ------ - -- --- ----- - --- ---------- --------- ---------------------------- --------- ------- ----------- -- -- --------- -------- ------ ---- ----------- ------- --------- --------- ------ ----------- ------ ------------- ------- ------------------- -- -- ------ ------- ---- --- ------- ---------
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 defineProperty
拦截器,拦截了 proxy
对象的定义属性的操作,输出被定义的属性名和属性描述符并调用 Object.defineProperty(target, prop, desc)
方法。
getPrototypeOf 拦截器
getPrototypeOf
拦截器用于拦截获取一个对象的原型的操作,例如 Object.getPrototypeOf(obj)
。其接收一个参数:
- target:被代理的对象。
以下是一个 getPrototypeOf
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - --------------- -------- -- - -------------------- --------- -- --------- ------ ------------------------------ - -- --- ----- - --- ---------- --------- ------------------------------------------ -- -- -------- --------- -- ----------- ----------------
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 getPrototypeOf
拦截器,拦截了 proxy
对象的获取原型的操作,输出被代理的对象并调用 Object.getPrototypeOf(target)
方法。
setPrototypeOf 拦截器
setPrototypeOf
拦截器用于拦截设置一个对象的原型的操作,例如 Object.setPrototypeOf(obj, proto)
。其接收两个参数:
- target:被代理的对象;
- proto:要设置的新原型对象。
以下是一个 setPrototypeOf
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - --------------- -------- ------ -- - -------------------- --------- -- ------ -- ----------- ------ ----------------------------- ------- - -- --- ----- - --- ---------- --------- ---------------------------- ---- ------------------------------------------ -- -- -------- --------
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 setPrototypeOf
拦截器,拦截了 proxy
对象的设置原型的操作,输出被代理的对象和新的原型对象并调用 Object.setPrototypeOf(target, proto)
方法。
isExtensible 拦截器
isExtensible
拦截器用于拦截检测一个对象是否可扩展的操作,例如 Object.isExtensible(obj)
。其接收一个参数:
- target:被代理的对象。
以下是一个 isExtensible
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - ------------- -------- -- - --------------------- -- ------ -- ------------- ------ ---------------------------- - -- --- ----- - --- ---------- --------- ---------------------------------------- -- -- --------- -- ------ -- --------------- ----
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 isExtensible
拦截器,拦截了 proxy
对象的检测是否可扩展的操作,输出被代理的对象并调用 Object.isExtensible(target)
方法。
preventExtensions 拦截器
preventExtensions
拦截器用于拦截使一个对象不可扩展的操作,例如 Object.preventExtensions(obj)
。其接收一个参数:
- target:被代理的对象。
以下是一个 preventExtensions
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - ------------------ -------- -- - ----------------------- ------ ---- ----- ----------- ------ --------------------------------- - -- --- ----- - --- ---------- --------- -------------------------------- ---------------------------------------- -- -- ----------- ------ ---- ----- ------------- -----
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 preventExtensions
拦截器,拦截了 proxy
对象的使其不可扩展的操作,输出被代理的对象并调用 Object.preventExtensions(target)
方法。
ownKeys 拦截器
ownKeys
拦截器用于拦截获取一个对象自身属性键名的操作,例如 Object.getOwnPropertyNames(obj)
或 Object.getOwnPropertySymbols(obj)
或 Reflect.ownKeys(obj)
。其接收一个参数:
- target:被代理的对象。
以下是一个 ownKeys
拦截器的代码示例:
-- -------------------- ---- ------- --- --- - - ----- ------- ---- -- -- --- ------- - - -------- -------- -- - -------------------- --- -------- ---- -- --------- ------ ----------------------------------- - -- --- ----- - --- ---------- --------- ----------------------------------------------- -- -- -------- --- -------- ---- -- ----------- -------- ------
在以上代码中,我们定义了一个对象 obj
,包含 name
、age
两个属性。我们还定义了一个 ownKeys
拦截器,拦截了 proxy
对象的获取其自身属性键名的操作,输出被代理的对象并调用 Object.getOwnPropertyNames(target)
方法。
Proxy 对象的符号键
除了上述拦截器类型,Proxy 对象还支持一些特殊的符号键,用于进行属性访问拦截、代理的相关操作。以下是常用的几种符号键:
get(target, prop, receiver)
:拦截对象的属性读取操作;set(target, prop, value, receiver)
:拦截对象的属性设置操作;has(target, prop)
:拦截in
操作符;deleteProperty(target, prop)
:拦截delete
操作符;apply(target, thisArg, args)
:拦截函数调用;construct(target, args)
:拦截构造函数调用。
其它符号键的使用方法和用途,请参考 MDN 文档。
总结
通过本文介绍,我们了解了 ES6 中的 Proxy 对象的基本用法和特性。Proxy 对象的拦截器类型和符号键,可以让我们更加灵活地处理对象的属性访问、方法调用、构造器调用等操作,为我们的编码提供了很大的方便和开发效率。经过深入的学习和练习,我们可以更好地掌握 Proxy 对象的使用方法,并在实际的项目开发中灵活运用。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65a99fa4add4f0e0ff2fd314