JavaScriptにおける遅延負荷属性パターンについて説明します。


はじめに
従来、開発者はJavaScriptクラスにおいて、インスタンスに必要な任意のデータの属性を作成する。コンストラクタ内でいつでも利用できる小さいサイズのデータについては問題ではない。しかし、例で使用できる前に、いくつかのデータを計算する必要がある場合、料金は前払いしたくないかもしれません。例えば、このクラスを考慮します。

class MyClass {
    constructor() {
        this.data = someExpensiveComputation();
    }
}
ここで、data属性は、いくつかの高価な計算を実行した結果として作成される。この属性が使用されるかどうかを判断しないと、計算を事前に実行するのは効率的ではないかもしれません。幸いにも、これらの操作を後で遅らせる方法はいくつかあります。
二、必要な属性モードで
高価な動作を最適化するための最も簡単な方法は、データが必要になってから計算することである。例えば、getterを持つアクセス属性を使用して、必要に応じて計算することができます。

class MyClass {
    get data() {
        return someExpensiveComputation();
    }
}
この場合、data属性を初めて読み込む人がいる時には、高価な計算が発生します。これは改良されています。しかし、dataが属性を読み出すたびに、同じ高価な計算が行われ、これは前の例よりも悪く、少なくとも一回の計算しか実行されていない。これは良い解決策ではありませんが、これに基づいてより良い解決策を作成することができます。
三、乱れた遅延荷重属性モード
属性にアクセスしたときだけ計算を実行するのは良いスタートです。本当に必要なのは、この時点の後に情報をキャッシュし、キャッシュバージョンのみを使用することです。しかし、これらの情報をどこにキャッシュしてアクセスしやすいですか?最も簡単な方法は、同じ名前の属性を定義し、その値を計算データに設定することです。

class MyClass {
    get data() {
        const actualData = someExpensiveComputation();
 
        Object.defineProperty(this, "data", {
            value: actualData,
            writable: false,
            configurable: false,
            enumerable: false
        });
 
        return actualData;
    }
}
ここで、data属性は再びクラスのgetterとして定義されているが、今回は結果をキャッシュしている。呼び出しObject.defineProperty()は、固定値dataを有し、書き込み不可、構成可能、およびエニュメレーション不可に設定された新しい属性actualDataを作成する。その後、値自体を返します。次にdataがこの属性にアクセスすると、getterを呼び出す代わりに、新しく作成された属性から読み取ります。

const object = new MyClass();
 
// calls the getter
const data1 = object.data;
 
// reads from the data property
const data2 = object.data;
実際には、すべての計算は、最初のdataで属性を読み出すときにのみ行われる。data属性の後続の読み出しの度にキャッシュのバージョンが返される。
このようなモードの欠点の一つはdata属性の始まりは列挙できないプロトタイプの属性であり、最終的には列挙できない自分の属性である。

const object = new MyClass();
console.log(object.hasOwnProperty("data"));     // false
 
const data = object.data;
console.log(object.hasOwnProperty("data"));     // true
この違いは多くの場合重要ではないが、このパターンを理解することは、相手を伝える時に微妙な問題を引き起こす可能性があるので、重要である。幸い、この問題は更新されたパターンを使って解決しやすいです。
四、クラスの唯一の自己の遅延荷重属性モード
遅延ローディングの属性が常にインスタンスに重要である場合、Object.defineProperty()を使用してクラス構造関数に属性を作成することができます。前の例に比べて混乱していますが、この属性はインスタンスのみに存在することを確認します。以下は一例です。

class MyClass {
    constructor() {

        Object.defineProperty(this, "data", {
            get() {
                const actualData = someExpensiveComputation();

                Object.defineProperty(this, "data", {
                    value: actualData,
                    writable: false,
                    configurable: false
                });

                return actualData;
            },
            configurable: true,
            enumerable: true
        });

    }
}
ここで、構造関数dataObject.defineProperty()を使用して、例で作成された(thisを使用して)getterを定義し、エニュメレート・構成可能な(典型的な自己の属性)属性を指定する。data属性は、Object.defineProperty()が再度起動できるように構成可能に特に重要である。
次いで、getter関数は計算され、再びObject.defineProperty()を呼び出す。data属性は、現在、特定の値を有するデータ属性として再定義され、最終データを保護するために書き込み可能でなく、構成可能でない。そして、計算データはgetterから戻ります。次にdataで属性を読み出すと、記憶されている値から読み出します。このdata財産は現在、自分の財産としてのみ存在しており、初めて読む前と後の行為は同じです。

const object = new MyClass();
console.log(object.hasOwnProperty("data"));     // true
 
const data = object.data;
console.log(object.hasOwnProperty("data"));     // true
クラスに対して、これはおそらくあなたが使うモードです。一方、対象文字はより簡単な方法で使用できる。
五、対象の字面量の遅延荷重属性パターン
クラスではなくオブジェクトの字面量を使うと、プロセスはより簡単になります。オブジェクトの字面量で定義されたgetterは、列挙可能な自己属性として定義されています。データ属性と同じです。これは、オブジェクトに対して乱れない属性モードをマウントするためにクラスに対して使用できることを意味します。

const object = {
    get data() {
        const actualData = someExpensiveComputation();
 
        Object.defineProperty(this, "data", {
            value: actualData,
            writable: false,
            configurable: false,
            enumerable: false
        });
 
        return actualData;
    }
};
 
console.log(object.hasOwnProperty("data"));     // true
 
const data = object.data;
console.log(object.hasOwnProperty("data"));     // true
六、結論
JavaScriptでオブジェクト属性を再定義する能力は、計算コストの高い情報をキャッシュするためのユニークな機会を提供する。データ属性として再定義されたアクセス属性から、最初の読み取り属性に計算を遅らせてから、後で使用するために結果をキャッシュします。この方法はクラスにも適用されますし、対象の字面量にも適用されます。対象の字面の量はもっと簡単です。あなたのゲッターが原型の上で終わることを心配する必要がないからです。
性能を向上させるための最良の方法の一つは、同じ作業の繰り返しを避けることであり、いつでも結果をキャッシュして後で使うことができ、プログラムの実行速度を速めることができます。遅延負荷属性モードなどの技術は、いずれの属性もキャッシュ層となり、性能を向上させることができる。
以上はJavaScriptの中の遅延負荷属性モードの詳細についてお話ししました。JS遅延負荷属性モードに関する資料は他の関連記事に注目してください。