We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
对象代理在日常开发中并不常用,因为它是针对编程语言进行编程,属于一种“元编程”。换句话来说,下面介绍的 Proxy 构造器 和 Reflect 内置对象,都可以针对 JavaScript 这门编程语言相关的原生功能,进行自定义新增、扩展、修改、删除、屏蔽等操作。
vue 3.0 将引入ES6中的 Proxy 替代原有ES5的 Object.defineProperty 方法,来实现数据双向绑定等功能。
Proxy
Object.defineProperty
Proxy 从字面上可以理解为 “代理”,更准确得来说,它对目标对象的属性访问、设置,或者函数调用等操作进行拦截(处理)。
语法
var proxy = new Proxy(target, handler);
Proxy 构造器接收两个参数,分别是 target 和 handle。其中 target 参数是目标(被代理/被拦截)对象,而 handler 参数也是对象,用来定制拦截(代理)行为。
target
handle
handler
实例1
我们先看最简单的拦截对象属性读取的例子:
// 普通对象 var obj = { foo: 0 } // 代理对象 var proxy = new Proxy(obj, { get (target, key, receiver) { return 1; } }); console.log(obj.foo); // 0 console.log(obj.bar); // undefined console.log(proxy.foo); // 1 console.log(proxy.bar); // 1
obj 是普通对象,获取不存在的属性,会返回 undefined;proxy 是代理对象,它对属性获取进行拦截,无论获取什么属性(是否存在),都返回 1。
obj
undefined
proxy
实例2
接着,我们再看看对象的 set 和 get 方法进行拦截。
set
get
var proxy = new Proxy({}, { get (target, key, receiver) { console.log(`Getting ${key}!`); return Reflect.get(target, key, receiver); }, set (target, key, value, receiver) { console.log(`Setting ${key},Value is ${value}!`); return Reflect.set(target, key, value, receiver); } }); proxy.count = 1; proxy.count++; // 输出 // Setting count,Value is 1! // Getting count! // Setting count,Value is 2!
这里,我们代理对象 proxy 对属性的设置和获取(对应着ES5中的set/get的访问器)都进行了拦截,都会自动输出相应的信息。Reflect 是ES6中的一个内置对象,类似于 Math,后面将详细介绍。
Reflect
Math
实例3
代理对象会对目标对象进行“浅拷贝”,相互影响。
var target = { a: 1, b: 2 }; var proxy = new Proxy(target, { get (target, key, receiver) { console.log(`Getting ${key}!`); return Reflect.get(target, key, receiver); }, set (target, key, value, receiver) { console.log(`Setting ${key},Value is ${value}!`); return Reflect.set(target, key, value, receiver); } }); proxy.a++; console.log(target.a); target.c = 3; console.log(proxy.c); // 输出 // Getting a! // Setting a,Value is 2! // 2 // Getting c! // 3
根据以上的代码,我们可以发现,代理对象 proxy 只是对 目标对象 target 的 set 和 get 操作进行拦截,输出相应的信息,并未改变原始对象数据的存取。
实例4
Proxy 实例也可以作为其他对象的原型对象。
var proxy = new Proxy({}, { get: function(target, property) { return 35; } }); var obj = Object.create(proxy); obj.time // 35
上面代码中,proxy 对象是 obj 对象的原型,obj对象本身并没有 time 属性,所以根据原型链,会在 proxy 对象上读取该属性,导致被拦截。
time
Proxy 支持 13 种拦截操作:
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(...args)
proxy.call(object, ...args)
proxy.apply(...)
construct(target, args)
new proxy(...args)
Reflect 从字面上可以理解为 “反射”,C# 也有类似的反射操作。它包含了对象语言内部的方法,一共有13种静态方法,与 Proxy 中的 hanlder参数支持的方法一一对应。Proxy 相当于去修改设置对象的属性行为,而 Reflect 则是获取对象的这些行为。
hanlder
设计目的
1) 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上。也就是说,从 Reflect 对象上可以拿到语言内部的方法。
Object
2)修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc) 在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc) 则会返回false。
Object.defineProperty(obj, name, desc)
Reflect.defineProperty(obj, name, desc)
false
// 老写法 try { Object.defineProperty(target, property, attributes); // success } catch (e) { // failure } // 新写法 if (Reflect.defineProperty(target, property, attributes)) { // success } else { // failure }
3) 让 Object 操作都变成函数行为。某些 Object 操作是命令式,比如name in obj和delete obj[name],而 Reflect.has(obj, name) 和 Reflect.deleteProperty(obj, name) 让它们变成了函数行为。
name in obj
delete obj[name]
Reflect.has(obj, name)
Reflect.deleteProperty(obj, name)
// 老写法 'assign' in Object // true delete object.foo // true // 新写法 Reflect.has(Object, 'assign') // true Reflect.deleteProperty(object, 'foo') // true
4)Reflect 对象的方法与 Proxy 对象的方法一一对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法。这就让 Proxy 对象可以方便地调用对应的 Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管 Proxy 怎么修改默认行为,你总可以在 Reflect 上获取默认行为。
var proxy = new Proxy({}, { get (target, key, receiver) { console.log(`Setting ${key}!`); Reflect.set(target, key, receiver); } });
Reflect 具有 13 个静态方法,暂时没有实例属性以及实例方法,详情可点击以下参考链接学习。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
对象代理在日常开发中并不常用,因为它是针对编程语言进行编程,属于一种“元编程”。换句话来说,下面介绍的 Proxy 构造器 和 Reflect 内置对象,都可以针对 JavaScript 这门编程语言相关的原生功能,进行自定义新增、扩展、修改、删除、屏蔽等操作。
vue 3.0 将引入ES6中的
Proxy
替代原有ES5的Object.defineProperty
方法,来实现数据双向绑定等功能。Proxy
Proxy 从字面上可以理解为 “代理”,更准确得来说,它对目标对象的属性访问、设置,或者函数调用等操作进行拦截(处理)。
语法
Proxy
构造器接收两个参数,分别是target
和handle
。其中target
参数是目标(被代理/被拦截)对象,而handler
参数也是对象,用来定制拦截(代理)行为。实例1
我们先看最简单的拦截对象属性读取的例子:
obj
是普通对象,获取不存在的属性,会返回undefined
;proxy
是代理对象,它对属性获取进行拦截,无论获取什么属性(是否存在),都返回 1。实例2
接着,我们再看看对象的
set
和get
方法进行拦截。这里,我们代理对象
proxy
对属性的设置和获取(对应着ES5中的set/get的访问器)都进行了拦截,都会自动输出相应的信息。Reflect
是ES6中的一个内置对象,类似于Math
,后面将详细介绍。实例3
代理对象会对目标对象进行“浅拷贝”,相互影响。
根据以上的代码,我们可以发现,代理对象
proxy
只是对 目标对象target
的set
和get
操作进行拦截,输出相应的信息,并未改变原始对象数据的存取。实例4
Proxy 实例也可以作为其他对象的原型对象。
上面代码中,
proxy
对象是obj
对象的原型,obj
对象本身并没有time
属性,所以根据原型链,会在proxy
对象上读取该属性,导致被拦截。Proxy 支持 13 种拦截操作:
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)
。Reflect
Reflect 从字面上可以理解为 “反射”,C# 也有类似的反射操作。它包含了对象语言内部的方法,一共有13种静态方法,与
Proxy
中的hanlder
参数支持的方法一一对应。Proxy
相当于去修改设置对象的属性行为,而Reflect
则是获取对象的这些行为。设计目的
1) 将
Object
对象的一些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上。现阶段,某些方法同时在Object
和Reflect
对象上部署,未来的新方法将只部署在Reflect
对象上。也就是说,从Reflect
对象上可以拿到语言内部的方法。2)修改某些
Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。3) 让
Object
操作都变成函数行为。某些Object
操作是命令式,比如name in obj
和delete obj[name]
,而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)
让它们变成了函数行为。4)
Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy
怎么修改默认行为,你总可以在Reflect
上获取默认行为。Reflect 具有 13 个静态方法,暂时没有实例属性以及实例方法,详情可点击以下参考链接学习。
参考链接
The text was updated successfully, but these errors were encountered: