es 6のメタプログラミング
3478 ワード
何が元プログラミングですか
「言語文法の特性や実行時の特性を変えるプログラムを作成する」.言い換えれば、言語では本来できないことが、プログラミングによって修正され、それができるようになりました.これは元プログラムです.
meta-programming元プログラミングにおける要素の概念は、プログラム自体として理解できます.」元プログラムは、プログラム自体を拡張する能力を持つことができます.
例を挙げます
これは元のプログラムで変えられます.これは不可能です.
proxy
es 5のObject.defineProperty()方法のes 6レベルアップ版は、カスタマイズする対象の行為に用いられます.
装飾器を通してクラスにカスタム情報を追加することができます.これらの情報は反射によって抽出される.もちろんあなたも反射によってこれらの情報を追加することができます.
拡張配列インデックスアクセス
マイナスインデックスアクセスは、
「言語文法の特性や実行時の特性を変えるプログラムを作成する」.言い換えれば、言語では本来できないことが、プログラミングによって修正され、それができるようになりました.これは元プログラムです.
meta-programming元プログラミングにおける要素の概念は、プログラム自体として理解できます.」元プログラムは、プログラム自体を拡張する能力を持つことができます.
例を挙げます
if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
この条件を満たすにはどうすればいいですか?正常なロジックでは完成できません.一つの値は同時に1、2、3に等しいです.これは元のプログラムで変えられます.これは不可能です.
let a = {
[Symbol.toPrimitive]: ((i) => () => ++i)(0)
}
if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
// done
Symbol.toPrimitive
は、オブジェクトが元の値に変換されると呼び出され、初期値は1であり、1回の+1を呼び出すとa == 1 && a == 2 && a == 3
を満たすことができ、一方、Symbol.toPrimitive
は、1つのパラメータhintを受け入れることができ、hintの取得値はnumber、string、defaultである.let obj = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case "number":
return 123;
case "string":
return "str";
case "default":
return "default";
}
}
}
console.log(1-obj); // -122
console.log(1+obj); // 1default
console.log(`${obj}`); // str
他にはどのような元のプログラミングがありますか?proxy
es 5のObject.defineProperty()方法のes 6レベルアップ版は、カスタマイズする対象の行為に用いられます.
let leon = {
age: 30
}
const validator = {
get: function(target, key){
// 37
return key in target ? target[key] : 37;
},
set(target,key,value){
if(typeof value!="number" || Number.isNaN(value)){
throw new Error(" ");
}
}
}
const proxy = new Proxy(leon,validator);
console.log(proxy.name);
// 37
proxy.age = "hi";
// Error:
reflect-metadata装飾器を通してクラスにカスタム情報を追加することができます.これらの情報は反射によって抽出される.もちろんあなたも反射によってこれらの情報を追加することができます.
require("reflect-metadata")
class C {
// @Reflect.metadata(metadataKey, metadataValue)
method() {
}
}
Reflect.defineMetadata("name", "jix", C.prototype, "method");
let metadataValue = Reflect.getMetadata("name", C.prototype, "method");
console.log(metadataValue);
// jix
適用拡張配列インデックスアクセス
マイナスインデックスアクセスは、
array[-N]
がarray[array.length - N]
と同じようにする.let array = [1, 2, 3];
array = new Proxy(array, {
get(target, prop, receiver) {
if (prop < 0) {
console.log(prop, 'prop')
prop = +prop + target.length;
}
return Reflect.get(target, prop, receiver);
}
});
console.log(array[-1]); // 3
console.log(array[-2]); // 2
データハイジャックlet handlers = Symbol('handlers');
function makeObservable(target) {
// handler
target[handlers] = [];
// handler
target.observe = function(handler) {
this[handlers].push(handler);
};
//
return new Proxy(target, {
set(target, property, value, receiver) {
//
let success = Reflect.set(...arguments);
//
if (success) {
// handler
target[handlers].forEach(handler => handler(property, value));
}
return success;
}
});
}
let user = {};
user = makeObservable(user);
user.observe((key, value) => {
console.log(`SET ${key}=${value}`);
});
user.name = "John";
// SET name=John