Proxy 和 defineProperty 的比较

Proxy 和 defineProperty 的比较

可拦截属性的比较

属性 defineProperty Proxy 描述
get 支持 支持 (target, propKey, receiver)
拦截对象属性的读取,比如 proxy.foo 和proxy[‘foo’]。
set 支持 支持 (target, propKey, value, receiver)
拦截对象属性的设置,比如proxy.foo = v 或 proxy[‘foo’] = v,返回一个布尔值。
has 不支持 支持 (target, propKey)
拦截 propKey in proxy 的操作,返回一个布尔值。
deleteProperty 不支持 支持 (target, propKey)
拦截 delete proxy[propKey] 的操作,返回一个布尔值。
ownKeys 不支持 支持 (target)
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor 不支持 支持 (target, propKey)
拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty 不支持 支持 (target, propKey, propDesc)
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions 不支持 支持 (target)
拦截 Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf 不支持 支持 (target)
拦截 Object.getPrototypeOf(proxy),返回一个对象。
isExtensible 不支持 支持 (target)
拦截 Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf 不支持 支持 (target, proto)
拦截 Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply 不支持 支持 (target, object, args)
拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
construct 不支持 支持 (target, args)
拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。

## 兼容性的比较 ### proxy的兼容性如下
desktopmobileserver
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebView AndroidChrome AndroidFirefox for AndroidOpera AndroidSafari on iOSSamsung InternetNode.js
Proxy
Proxy() constructor
revocable

### defineProperty兼容性如下
desktopmobileserver
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebView AndroidChrome AndroidFirefox for AndroidOpera AndroidSafari on iOSSamsung InternetNode.js
defineProperty

使用总结

  • Object.defineProperty 并非不能监控数组下标的变化(vue2中不能通过下标的方式更新数组)
  • Object.defineProperty 对属性的劫持需要深度遍历,新增属性需要手动Observe
  • Proxy 可以使用业务场景和支持的API更多和全面
  • Proxy 作为新标准,后续会有持续的性能优化
  • Proxy 兼容性是硬伤,在对兼容性有要求的业务场景下无法使用