Skip to content

Latest commit

 

History

History
100 lines (72 loc) · 4.19 KB

元编程.md

File metadata and controls

100 lines (72 loc) · 4.19 KB

元编程

关于元编程到底是什么意思,可以参见 怎么理解元编程?

我的理解是,可以改变程序原有的默认行为,例如数组的内置方法、对象的原型链方法、字符串属性等,就叫元编程

JavaScript中,evalnew FunctionProxyReflectSymbols 都是可用于进行元编程的特性

eval

eval('function a(){console.log(2)};a()')
// 执行输出 => 2

eval执行了一段字符串,将字符串当成代码执行,却让这段字符串拥有了函数般的能力,所以可以算是元编程

new Function

// args 是传入函数的参数,functionBody是 字符串形式的函数体
new Function ([arg1[, arg2[, ...argN]],] functionBody)
const fn = new Fcuntion(a, b, 'return a + b')
fn(2, 3)  // ==> 5

new Function 将自己的字符串参数当成代码来执行,拼装成了一个函数

Proxy

ES6 新增特性

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种 元编程(meta programming),即对编程语言进行编程

const obj = new Proxy({}, {
  get(target, key, receiver) {
    return target[key]
  },
  set(target, key, value, receiver) {
    target[key] = value % 2 === 0 ? 2 * value : value
  }
})

obj.age = 4
obj.gender = 1
console.log(obj.age)  // => 8
console.log(obj.gender)  // => 1

Proxy 共支持 13种拦截操作:

  • get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.foo和proxy['foo']
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如 proxy.foo = vproxy['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更多参见 proxy

Reflect

ES6 新增特性

Reflect的特性有如下几点:

  • Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到 Reflect对象上
  • 修改某些 Object方法的返回结果,让其变得更合理
  • Object操作都变成函数行为。某些 Object操作是命令式
  • Reflect对象的方法与 Proxy对象的方法一一对应,只要是 Proxy对象的方法,就能在 Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的 Reflect方法,完成默认行为

Reflect 存在 13个静态方法,与 Proxy13个拦截操作一一对应

Symbol

ES6 新增特性,一种新的原始数据类型

const obj = {
  toString() {
    return 'abc'
  }
}

const sym = Symbol(obj)
console.log(sym)  // => Symbol(abc)

Symbol改变了 obj默认的 toString方法,可以认为是一种元编程