元编程 是一种编程技术,编写出来的计算机程序能够将其他程序作为数据来处理。意味着可以编写出这样的程序:它能够读取、生成、分析或者转换其它程序,甚至在运行时修改程序自身。 简而言之,元编程能够写出这样的代码:
- 可以生成代码
- 可以在运行时修改语言结构,这种现象被称为 反射编程 或 反射
几个概念
Symbol
概念
用symbol声明的变量是独一无二的,不可能重复
let a1 = Symbol()
let a2 = Symbol()
a1 === a2 // false
let a3 = Symbol.for('a3')
let a4 = Symbol.for('a3') // 用for定义的,相同key只会生成一次,后面每次取之前的值
a3 === a4 // true
作用
let a1 = Symbol.for('abc') // 和'abc'不会冲突
let obj = {
[a1]: '123',
'abc': 345,
'c': 456
}
// 注意: for...of和for...in都是拿不到Symbol定义的属性
Object.getOwnPropertySymbols(obj).forEach(item => {
console.log(item) // 123 只能拿到symbol定义的属性
})
// 要拿到包含symbol的所有属性
Reflect.ownKeys(obj).forEach(item => {
console.log(item, obj[item])
})
Proxy和Reflect(API基本相同)
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一 种“元编程”(meta programming),即对编程语言进行编程。 --阮一峰《es6标准入门》
Reflect 改变直接用点语法取对象的习惯,用反射 读取对象
Proxy和Reflect的适用场景
let obj = {
time: '2021-3-3',
name: 'aaa',
_r: 123
}
// 通过代理生成个新对象,最后用户访问的是monitor
let monitor = new Proxy(obj, {
// 拦截对象属性的读取
get(target, key) {
} // console.log(monitor.time)
// 拦截对象设置属性
set(target, key, value) {
} // monitor.name = 'a'
// 拦截 判断对象中是否有某个属性 in
has(target, key) {
}
// 拦截 删除属性操作
deleteProperty(target, key) {
if (key.indexOf('_') > -1) {
delete target[key]
return true
} else {
return target[key]
}
}
// 拦截Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter(item => item != 'time')
}
})
delete monitor.time
delete monitor._r
let obj = {
time: '2021-3-3',
name: 'aaa',
_r: 123
}
console.log(Reflect.get(obj, 'time') // 2021-3-3
Reflect.set(obj, 'name', '张三')
Reflect.has(obj, 'name') // true
用proxy和reflect实现校验
function validator(target, validator) {
return new Proxy(target, {
_validator: validator,
set(target
}
}
用元编程实现表单
表单,自然就是字段的 name,label,require,validate,以及提交数据的转换。
- 我们还是先收集 form 所需的元数据结构
- 有了元数据,我们可以在 一个 Class 中生成 form 所需
- initialValues
- 数据校验的 validationSchema
- 各个表单组件所需的,name,label,required 等
- 提交表单的数据转换 handle 函数