You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Just like metadata is data about data, metaprogramming is writing programs that manipulate programs. It's a common perception that metaprograms are the programs that generate other programs. But the paradigm is even broader. All of the programs designed to read, analyze, transform, or modify themselves are examples of metaprogramming. Metaprogramming in Python
元编程
元编程(meta-programming)一般分为两类,一是在编译时生成代码,二是在运行时修改代码行为。
Proxy
在 JavaScript 中,Proxy 属于元编程的一种。
简介
如果你问我多大,通过
person.age
访问得到20
。但这届年轻人,总是说「别问,问就是 18」,那么我会创建一个替身:
这样,再问我年龄时,你问的其实是
substitute
,此时substitute.age
是 18。尽管我真实年龄person.age
是 20。Proxy 通常用于修改某些操作的默认行为。比如,别人访问我的年龄,讲道理应该返回真实年龄(默认行为),但由于某些原因(心情不爽),就告诉你我 18。
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
基础语法
target
- 被代理的对象(下文称为源对象)。可以是任意类型的对象,比如数组、函数、另一个代理对象等。handler
- 一个含有特定方法的对象。其中
handler
有以下方法:handler.get()
handler.set()
handler.has()
handler.apply()
handler.construct()
handler.defineProperty()
handler.deleteProperty()
handler.getOwnPropertyDescriptor()
handler.getPrototypeOf()
handler.setPrototypeOf()
handler.ownKeys()
handler.isExtensible()
handler.preventExtensions()
一个无操作转发代理:
get/set 方法
用于拦截对象的读取、赋值。
当读取
proxy.name
或赋值proxy.name = 'foo'
就会对应触发get
、set
方法。参数:
target
- 源对象。property
- 被读取/赋值的属性名。value
- 将被赋值的值(仅set
方法有)。receiver
- 最初接收赋值的对象。通常是代理实例本身。返回值:
get()
方法可返回任意值。set()
方法返回布尔值,true
表示属性设置成功。约束:
receiver
不是代理实例本身的反例:当读取
empty.foo
时,因本身没有foo
属性,则从原型链proxy
上找,触发get
方法,此时打印结果分别是false
、true
。也就是说,此时的receiver
为empty
对象,而非proxy
实例。其他方法
除了最常用的拦截属性读写操作之外,还可以拦截以下操作:
get()
set()
has()
in
操作符的拦截。apply()
construct()
new
操作符的构造函数调用的拦截。defineProperty()
Object.defineProperty()
操作的拦截。deleteProperty()
delete
操作符删除属性的拦截。getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor()
操作的拦截。getPrototypeOf()
Object.getPrototypeOf()
、Object.prototype.__proto__
、Object.prototype.isPrototypeOf()
、instanceof
操作的拦截。setPrototypeOf()
Object.setPrototypeOf()
操作的拦截。ownKeys()
Reflect.ownKeys()
操作的拦截。isExtensible()
Object.isExtensible()
操作的拦截。preventExtensions()
Object.preventExtensions()
操作的拦截。应用场景
防止访问私有属性。
数组负值索引:
为什么 Vue 使用 Proxy 代替 Object.defineProperty?
关于
Object.defineProperty()
缺点:set
、delete
。push
、pop
等方式。这些问题在 Proxy 上都有较好且完整的支持。
但 Proxy 兼容性没那么好。它无法 polyfill。
源码:
Proxy 性能
Reflect
Reflect 是一个内置「对象」。它不是函数,自然也不能当作普通函数或使用
new
关键字调用。它跟 Proxy 的 handler 有着同名的方法:
Reflect.get()
Reflect.set()
Reflect.has()
Reflect.apply()
Reflect.construct()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.setPrototypeOf()
Reflect.ownKeys()
Reflect.isExtensible()
Reflect.preventExtensions()
Proxy 可以与 Reflect 搭配使用,前者负责拦截对象的操作,后者负责原有的默认行为。
设计 Reflect 的目的:
Reflect
上。类似于可迭代的Map
一样,假设未来要新增一种数据结构,也会基于可迭代的趋势去设计。Object
方法的返回结果,变得更合理。比如Reflect.defineProperty()
如果无法定义属性,就会返回false
,而不像Object.defineProperty()
在无法定义属性时抛出错误。delete obj[key]
删除属性,现在则是Reflect.deleteProperty(obj, key)
。References
The text was updated successfully, but these errors were encountered: