突然ですが、Rubyのメソッドメソッドって便利じゃないですか?コードを記述するときに、オブジェクトで使用できるすべてのメソッドとプロパティがリストされ、それらを検索できるため、デバッグに非常に役立ちます。
そのほか、Rails などのフレームワーク固有のメソッドを確認するのにも効果的で、コードの読み取りやライブラリの理解に役立ちます。公式ドキュメントやソース コードを参照することは良い習慣ですが、メソッド メソッドは、深く調べる必要がないライブラリやメソッド名の記憶が曖昧な場合に非常に役立ちます。
Ruby のメソッドメソッドを簡単に紹介すると、次のようになります。
オブジェクト#メソッド
obj のパブリック メソッドとプロテクト メソッドの名前のリストを返します。これには、obj の先祖でアクセスできるすべてのメソッドが含まれます。オプションのパラメータが false の場合、obj のパブリックおよび保護されたシングルトン メソッドの配列が返されます。配列には、obj.
に含まれるモジュールのメソッドは含まれません。
言い換えると、受信側からアクセスできるプロパティとメソッドの配列オブジェクトを返します。
このメソッドは、Object を継承するすべてのクラスの祖先である Object クラスに実装されているため、Object を継承する任意のクラスで使用できます。
サンプルコード
class Hoge attr_accessor :fuga def bar puts '' end end puts Hoge.new.methods // => [:bar, :fuga=, :fuga, :hash, :singleton_class, :dup, ...] puts Hoge.new.grep /fuga/ // => [:fuga=, :fuga]
例のように、Array オブジェクトを返すので、grep メソッドを使用してメソッドのリストを検索することもでき、非常に便利です。
そこで、これをJSで実現できないかと考え、試してみました。
以下は実際のコードです。
クラス名は何でも構いませんが、今のところ PropertyFinder という名前にします。
class PropertyFinder { constructor(receiver) { this.receiver = receiver } grep(regexp, options = {}) { let res = [] if (typeof regexp === 'string') { return this.find((name) => name.includes(regexp)) } if (regexp instanceof RegExp) { return this.find((name) => regexp.test(name)) } return [] } toString() { return this.find(() => true) } find(detect) { const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it)) if (!this.receiver.__proto__) { return list } const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect) return [...list, ...ancestors] } }
コードについては後ほど説明しますが、まずは使い方から見ていきましょう。
クラスを定義したら、次のようにオブジェクト クラスのプロパティにメソッドを追加できます。
Object.prototype.methods = function () { return new PropertyFinder(this) }
こうすることで、Objectを継承したクラスのインスタンスに対してmethodsメソッドを使用できるようになります。ただし、以下の注意事項をご理解の上、自己責任でご利用ください。
実行例をいくつか示します:
class Hoge { fuga() { console.log('fuga') } } console.log(new Object().methods().toString()) // => ['constructor', 'constructor', '__defineGetter__', '__defineSetter__', 'hasOwnProperty' ...] console.log([].methods().toString()) // => ['length', 'length', 'constructor', 'at', 'concat', ...] console.log(new Hoge().methods().grep(/fuga/) // => ['fuga']
*このコードは運用環境での使用は推奨されません *
モンキーパッチを通じて上位クラスにプロパティを追加することはアンチパターンであり、将来の JS 仕様の変更で問題が発生する可能性があります。ご自身の責任で慎重に使用してください。
参考:モンキーパッチングの短所
それでは、コードの説明に移りましょう。
PropertyFinder で最も重要なメソッドは find メソッドです。このメソッドは、指定されたオブジェクトのプロトタイプ チェーンを走査し、アクセス可能なプロパティを検索し、それらをリストとして返します。
toString メソッドと grep メソッドは単に find を使用するだけなので、これ以上の説明は必要ありません。
プロトタイプ チェーンに馴染みのない人もいるかもしれませんが、これは Object クラスからのプロパティの継承です。
継承とプロトタイプチェーン | MDN
詳細は MDN ドキュメントで説明されていますが、JavaScript の継承メカニズムはプロトタイプ チェーンによってサポートされています。
必ずしも明らかではありませんが、プロパティを参照する場合、そのプロセスには次のことが含まれます。
このプロセスは、一致するものが見つかるまでチェーンを上っていき、一致したものが返されます。
上記を考慮すると、PropertyFinder の find メソッドはこのメカニズムを実装しており、__proto__ を再帰的に探索することでプロパティのリストを取得できます。
これは、__proto__ を再帰的に探索してリストを取得することでこれを実現する実装です:
find(detect) { const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it)) if (!this.receiver.__proto__) { return list } const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect) return [...list, ...ancestors] }
以上でPropertyFinderの説明を終わります。
これで、コードと試したことの説明は終わりです。
これは実験的または遊び心のある演習でしたが、いくつかの知識とテクニックが含まれていたため、ご自身のアプリケーションに役立つ、またはインスピレーションを感じていただければ幸いです。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3