(Web関連用語)
https://qiita.com/kerupani129/items/2b3f2cba195c0705b2e5
クラスやメソッドに機能を追加するもの。(Java でいうアノテーション)
クラス
// 定義
const F = target => {
// target: クラス
// return target; // なくても良い
};
// 適用
@F // ★
class Foo { }
// やっていること
class Foo { }
Foo = F(Foo) || Foo; // ★
メソッド
// 定義
const F = (target, name, descriptor) => {
// target: クラスの prototype (※ this の代わりに使うとハマることがある)
// name: メソッド名
// descriptor: メソッドのディスクリプタ
// descriptor.value: メソッドそのもの
// descriptor.writable: false なら const
// return descriptor; // なくても良い
};
// 適用
class Foo {
@F // ★
bar() {}
}
// やっていること
class Foo {
bar() {}
}
// ★
(() => {
let bar = Object.getOwnPropertyDescriptor(Foo.prototype, 'bar');
bar = F(Foo.prototype, 'bar', bar) || bar;
if (bar) Object.defineProperty(Foo.prototype, 'bar', bar);
})();
※Object.getOwnPropertyDescriptor()、Object.defineProperty() はディスクリプタを読み書きする関数。
※ディスクリプタの enumerable, configurable は普段使わないと思うので省略。
アクセサ
ほぼメソッドと同じ(ディスクリプタの内容が異なる)。
// 定義
const F = (target, name, descriptor) => {
// target: this
// name: メソッド名
// descriptor: メソッドのディスクリプタ
// descriptor.get: getter そのもの
// descriptor.set: setter そのもの
// return descriptor; // なくても良い
};
// 適用
class Foo {
@F // ★
get bar() {}
set bar(value) {}
}
// やっていること
class Foo {
get bar() {}
set bar(value) {}
}
// ★ (メソッドと同じ)
(() => {
let bar = Object.getOwnPropertyDescriptor(Foo.prototype, 'bar');
bar = F(Foo.prototype, 'bar', bar) || bar;
if (bar) Object.defineProperty(Foo.prototype, 'bar', bar);
})();
オブジェクトのメソッド・アクセサ
オブジェクト定義の中のメソッド・アクセサでも同様に使用することができる。
const Foo = {
@F // ★
bar() {},
@F // ★
get baz() {},
set baz(value) {}
};
デコレータに引数を持たせる
デコレータを返す関数を定義する。
// 定義
const F = param => (target, name, descriptor) => {
// ...
};
// 適用
class Foo {
@F('Param') // ★ F('Param') == (target, name, descriptor) => {/* ... */}
bar() {}
}
複数のデコレータを同時に適用する
適用したいクラス・メソッド・アクセサの宣言に近いものから順に適用される。
// 適用
class Foo {
// ★ F → G → H
@H
@G
@F
bar() {}
}
具体的な使用例(@readonly)
// 定義
const readonly = (target, name, descriptor) => {
descriptor.writable = false;
};
// 適用
class Foo {
bar() {}
@readonly // ★
baz() {}
}
// 実行
const foo = new Foo();
foo.bar = () => {};
foo.baz = () => {}; // ★エラーが発生する