元编程

244 阅读2分钟

元编程 是一种编程技术,编写出来的计算机程序能够将其他程序作为数据来处理。意味着可以编写出这样的程序:它能够读取、生成、分析或者转换其它程序,甚至在运行时修改程序自身。 简而言之,元编程能够写出这样的代码:

  • 可以生成代码
  • 可以在运行时修改语言结构,这种现象被称为 反射编程 或 反射

几个概念

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 函数

segmentfault.com/a/119000000…