Open FrankKai opened 5 years ago
元编程(英语:Metaprogramming),又译超编程,是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。多数情况下,与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。 编写元程序的语言称之为元语言。被操纵的程序的语言称之为“目标语言”。一门编程语言同时也是自身的元语言的能力称之为“反射”或者“自反”。
引申问题:javascript是自身的元语言吗?es6之后是的,因为es6之后,js增加了反射。
var p = new Proxy(target, handler);
trap指的是对象的属性权限,类似操作系统中的trap。target可以是数组,对象或者是proxy。handler是包含了很多函数的对象,在其中定义各种各样的自定义行为,在元级别对对象做定义。经常用到的是handler.set(),handler.get(),除此之外还有:getPrototypeOf,setPrototypeOf,isExtensible,preventExtensions,getOwnPropertyDescriptor,defineProperty,has,deleteProperty,ownKeys,apply,construct。几乎每一个自定义行为在Object原型链上都有对应的trap。es6的Proxy允许我们拦截一个操作,然后实现自定义的行为。例如获取对象的一个属性:
var handler = {
get: function(target, name) {
return name in target ? target[name] : 42;
}
};
var p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 1, 42
除了上面的get trap proxy了对象的属性获取以外,还有很多可以使用Proxy的情况。
var target = {};var p = new Proxy(target, {});
上面的例子在Proxy有详细的介绍
如果学习过Proxy,其实已经对这里的术语很熟悉了。
关于Handler,Trap和Invariants。可以参考这个表格:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming#Handlers_and_traps
Proxy.revocable()用来创建可撤销的Proxy对象。 Proxy.revocable()与new Proxy()一样,都是创建了一个新的Proxy对象。
调用proxy.revoke()可以关闭proxy,关闭以后对于proxy的operation都会报出TypeError。
var revocable = Proxy.revocable({}, {
get: function(target, name) {
return '[[' + name + ']]';
}
});
var proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // TypeError is thrown
proxy.foo = 1; // TypeError again
delete proxy.foo; // still TypeError
typeof proxy; // "object", typeof doesn't trigger any trap
提供了拦截js操作的方法,有助于将默认操作从handler转发到target。
Reflect给人的感觉就是,自己对自己做一些操作更加直观。
类似于一个帮手。
Reflect.has(Object, "assign"); // true
Math.floor.apply(undefined, [1.75]);
Reflect.apply()使得代码更加精简且容易理解:
Reflect.apply(Math.floor, undefined, [1.75]); // 1;
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);// "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index;// 4
Reflect.apply(''.charAt, 'ponies', [3]);// "i"
Object.defineProperty定义成功返回的是对象,而Reflect返回的是Boolean值。
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
es6引入的元编程概念,个人认为在Proxy方面的体现比较大。 不过Object作为js中的第一公民,Reflect这个内建对象的引入,使得Proxy使用起来更加方便。
个人认为:Proxy主要作用于元编程definition,Reflect主要作用于元编程usage。
最近在看《深入浅出vue.js》作者屡次提到es6引入的元编程。 引入元编程前vue不能xxx,引入元编程后vue就可以xxx。 Proxy和Reflect倒是听说过,但是没有想过应用场景。 所以需要一探究竟元编程的原理,也为对学习未来版本的vue做一个铺垫。
学习资料: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming