ES6元编程

1.什么是元编程

元编程(Metaprogramming)是指某类计算机程序的编写,这类计算机程序编写或者操纵其他程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。很多情况下与手工编写全部代码相比工作效率更高。编写元程序的语言称之为元语言,被操作的语言称之为目标语言。一门语言同时也是自身的元语言的能力称之为反射。
以上概念来自百度,相对抽象,我们来看几个例子:

js元编程即对js本身进行编程。在某些条件下,js本身并不能满足我们的要求,这时候我们就需要对js内部执行过程进行修改。

例子:

var s = 1;
if (s == 1 && s == 2 && s == 3) {
    console.log('ezreal');
}

以上代码想打印出信息看似不可能,其实我们可以对js内部进行隐式转换的方式进行修改,修改代码如下:

var s = {
    value: 1,
    valueOf: () => s.value++
};
//方法二
// var s = {
//     [Symbol.toPrimitive]:(i => ()=>++i)(0)
// }
if (s == 1 && s == 2 && s == 3) {
    console.log('ezreal');
}

这就是一个简单的元编程的例子。方法二Symbol.toPrimitive 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。类似的还有Symbol.iterator等,当我们需要处理对象遍历时,想做一些别的操作,可以自定义迭代器:

var myIterable = {}
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable] // [1, 2, 3]

以上可以看出,当我们对js本身默认条件下给的值不满意或者达不到我们需求,需要改变js默认行为时,可以js本身来修改js,也就是开头说的反射。

2.Reflect和Proxy

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的。(以上概念摘自MDN)

Reflect也就是js里面的反射,因为他提供了拦截js的方法。例如当读取对象属性时,会触发对象的getter方法,但是当我们用Reflect.get方法去取时,就是单纯的去取值而不会触发对象的getter方法。

Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。(概念摘自MDN)
显然通过Proxy的概念我们就能看出它就是元编程。
下面看个例子

var a = {}
a.b.c.d = 'ezreal'
//输出 a
{ b: { c: { d:  'ezreal'  } } } 

默认情况下a.b是undefined,所以代码会报错。
下面通过代理的方式来实现它

function Tree() {
    return new Proxy({}, handler);
  }
  const handler = {
    get(target, key, receiver) {
      if (!(key in target)) {
        target[key] = Tree();
      }
      // return target[key];
      return Reflect.get(target, key, receiver);
    },
  };
let a = Tree();
a.b.c.d = 'ezreal';
console.log(a); //{ b: { c: { d: 'ezreal' } } }

注意我们在handler的get函数内部return的时候并没有直接返回target[key],而是通过Reflect.get去取值再返回。原因是当我们通过target[key]直接去拿属性时,js会默认触发getter,那就又回到get函数形成的无限递归,代码就废了。所以这里通过Reflect.get获取属性值。(vue3源码也是基于此实现的)

3.元编程库

  • reflect-metadata: https://www.npmjs.com/package/reflect-metadata

你可能感兴趣的:(ES6元编程)