ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)

JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)

黄舟
黄舟オリジナル
2017-03-11 15:27:531503ブラウズ

最近、私は Angular 開発者がインデックス付き DB などの WEB 標準を使用してクラウド データ、特に Azure モバイル サービスを使用できるようにするプロジェクト Angular Cloud Data Connector を開発しました。 JavaScript 開発者がプライベート メンバーをオブジェクトに埋め込む方法を作成しようとしています。

この問題を解決するための私のテクニックは、私が closurespace と名付けたものを使用します。この入門記事では、プロジェクトでの使用方法と、主要なブラウザーでのパフォーマンスとメモリへの影響について共有したいと思います。

詳しく学ぶ前に、まずプライベート メンバー (プライベート メンバー) を使用する必要がある理由について説明します。プライベート メンバーをシミュレートする別の方法もあります。

この記事にコメントしたい場合は、お気軽に @deltakosh までツイートしてください。

1. Private Members を使用する理由

JavaScript でオブジェクトを作成するときに、値メンバーを宣言できます。 それらへの読み取り/書き込みアクセスを制御する場合は、次のように宣言できます:

var entity = {};

entity._property = "hello world";
Object.defineProperty(entity, "property", {
    get: function () { return this._property; },
    set: function (value) {
        this._property = value;
    },
    enumerable: true,
    configurable: true
});

この方法で、読み取りおよび書き込み操作を完全に制御できます。問題は、_property メンバーに依然として直接アクセスして変更できることです。

これが、オブジェクト メソッドを通じてアクセスできる、プライベート メンバーを宣言するためのより安定した信頼性の高い方法が必要な理由です。

2. クロージャ スペースを使用する

解決策は、クロージャ スペースを使用することです。内部関数が外部関数のスコープから変数にアクセスするたびに、ブラウザーはメモリ空間を割り当てます。難しい場合もありますが、私たちの問題にとって、これは完璧な解決策です。

我们在上个代码版本中添加这个特性:
var createProperty = function (obj, prop, currentValue) 
{
    Object.defineProperty(obj, prop, 
    {
            get: function () { return currentValue; },
            set: function (value) {
            currentValue = value;
                    },
                    enumerable: true,
                    configurable: true    });
                    } 
var entity = {}; 
var myVar = "hello world";createProperty(entity, "property", myVar);

この例では、createProperty 関数に currentValue 変数があり、get メソッドと set メソッドがあります。この変数は、get 関数と set 関数のクロージャー空間に保存されます。これで、これら 2 つの関数のみが currentValue 変数を参照および更新できるようになりました! ミッションは完了しました! 唯一の注意、警告、注意は、ソース値 (myVar) にまだアクセスできることです。これは、別のより堅牢なバージョンです (myVar 変数を保護する):

var createProperty = function (obj, prop) {
    var currentValue = obj[prop];
    Object.defineProperty(obj, prop, {
        get: function () { return currentValue; },
        set: function (value) {
            currentValue = value;
        },
        enumerable: true,
        configurable: true
    });
}

var entity = {
    property: "hello world"
};

createProperty(entity, "property");

この関数を使用すると、ソース値も破棄されます (破棄されます。注: これは、値を直接割り当てることができないことを意味します)。以上です!

3. パフォーマンスに関する考慮事項

次に、パフォーマンスを見てみましょう。

明らかに、単純な変数、クロージャ スペース、さらには (オブジェクト) プロパティと比較すると、はるかに遅く、より多くのリソースを消費します。このため、この記事では通常の方法と閉鎖空間メカニズムの違いに重点を置きます。

クロージャ スペース メカニズムが標準の方法より多くのリソースを消費しないことを証明するために、ベンチマーク テストとして次のコードを作成しました:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<style>
    html {
        font-family: "Helvetica Neue", Helvetica;
    }
</style>
<body>
    <p id="results">Computing...</p>
    <script>
        var results = document.getElementById("results");
        var sampleSize = 1000000;
        var opCounts = 1000000;

        var entities = [];

        setTimeout(function () {
            // Creating entities
            for (var index = 0; index < sampleSize; index++) {
                entities.push({
                    property: "hello world (" + index + ")"
                });
            }

            // Random reads
            var start = new Date().getTime();
            for (index = 0; index < opCounts; index++) {
                var position = Math.floor(Math.random() * entities.length);
                var temp = entities[position].property;
            }
            var end = new Date().getTime();

            results.innerHTML = "<strong>Results:</strong><br>Using member access: <strong>" + (end - start) + "</strong> ms";
        }, 0);

        setTimeout(function () {
            // Closure space =======================================
            var createProperty = function (obj, prop, currentValue) {
                Object.defineProperty(obj, prop, {
                    get: function () { return currentValue; },
                    set: function (value) {
                        currentValue = value;
                    },
                    enumerable: true,
                    configurable: true
                });
            }
            // Adding property and using closure space to save private value
            for (var index = 0; index < sampleSize; index++) {
                var entity = entities[index];

                var currentValue = entity.property;
                createProperty(entity, "property", currentValue);
            }

            // Random reads
            var start = new Date().getTime();
            for (index = 0; index < opCounts; index++) {
                var position = Math.floor(Math.random() * entities.length);
                var temp = entities[position].property;
            }
            var end = new Date().getTime();

            results.innerHTML += "<br>Using closure space: <strong>" + (end - start) + "</strong> ms";
        }, 0);

        setTimeout(function () {
            // Using local member =======================================
            // Adding property and using local member to save private value
            for (var index = 0; index < sampleSize; index++) {
                var entity = entities[index];

                entity._property = entity.property;
                Object.defineProperty(entity, "property", {
                    get: function () { return this._property; },
                    set: function (value) {
                        this._property = value;
                    },
                    enumerable: true,
                    configurable: true
                });
            }

            // Random reads
            var start = new Date().getTime();
            for (index = 0; index < opCounts; index++) {
                var position = Math.floor(Math.random() * entities.length);
                var temp = entities[position].property;
            }
            var end = new Date().getTime();

            results.innerHTML += "<br>Using local member: <strong>" + (end - start) + "</strong> ms";
        }, 0);

    </script>
</body>
</html>

すべて属性メンバーを持つ 100 万個のオブジェクトを作成しました。次の 3 つのテストを完了するには:

    属性へのランダム アクセスを 100 万回実行します。
  • 100万ランダムアクセスクロージャスペース実装バージョンを実行します。
  • 通常の get/set 実装に対して 100 万回のランダム アクセスを実行します。
  • テスト結果を次の表とグラフに示します。

JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図) ブラウザによっては、クロージャ スペースの実装が従来の実装よりも常に高速であることがわかりました。

Chrome でのパフォーマンスが予想よりも低いです。バグがある可能性があるので、確認のためGoogleプロジェクトチームに連絡し、発生した症状を記載しました。また、Microsoft Edge (Windows 10 にデフォルトでインストールされている Microsoft の新しくリリースされたブラウザ) でのパフォーマンスをテストしたい場合は、クリックしてダウンロードできます。

しかし、注意深く研究すると、クロージャースペースまたは属性を使用すると、変数メンバーに直接アクセスするよりも約 10 倍時間がかかることがわかります。したがって、適切かつ注意して使用してください。

JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)4. メモリ使用量

また、このテクノロジーがメモリを過剰に消費しないことを確認する必要があります。メモリ使用量のベンチマークをテストするために、次のコード スニペットを作成しました:

直接属性参照バージョン (リファレンス コード)

var sampleSize = 1000000;
 var entities = []; 
// Creating entities
for (var index = 0; index < sampleSize; index++) {
    entities.push({
            property: "hello world (" + index + ")"
});}

通常の方法、取得/設定)

var sampleSize = 1000000;

var entities = [];

// Adding property and using local member to save private value
for (var index = 0; index < sampleSize; index++) {
    var entity = {};

    entity._property = "hello world (" + index + ")";
    Object.defineProperty(entity, "property", {
        get: function () { return this._property; },
        set: function (value) {
            this._property = value;
        },
        enumerable: true,
        configurable: true
    });

    entities.push(entity);
}

クロージャ スペース バージョン

var sampleSize = 1000000;

var entities = [];

var createProperty = function (obj, prop, currentValue) {
    Object.defineProperty(obj, prop, {
        get: function () { return currentValue; },
        set: function (value) {
            currentValue = value;
        },
        enumerable: true,
        configurable: true
    });
}

// Adding property and using closure space to save private value
for (var index = 0; index < sampleSize; index++) {
    var entity = {};

    var currentValue = "hello world (" + index + ")";
    createProperty(entity, "property", currentValue);

    entities.push(entity);
}

その後、3 つすべてを実行しました。 (3 つの主要なブラウザ上で) コードを実行し、(ブラウザの) 内蔵メモリ プロファイラを起動しました (この例では F12 ツールバーを使用):

JavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)Me コンピュータ上で実行した結果は次のとおりです:

クロージャ スペースと従来の方法に関しては、Chrome のみでクロージャ スペース (メモリ使用量) のパフォーマンスがわずかに優れています。IE11 と Firefox ではメモリ使用量が増加しますが、ブラウザの比較結果は、最新のブラウザの場合、ユーザーは次のような結果になる可能性があります。この違いは気にしないでください。

さらなる JavaScript 実践

Microsoft がオープンソース JavaScript のトピックに関する一連の無料学習教材を提供していることに驚かれたかもしれません。また、Microsoft Edge Coming シリーズをさらに作成するというミッションを開始しています。 私の記事をチェックしてください:

  • HTML5 と Babylon.JS に基づいた WebGL 3D の基本の開発

  • ASP.NET と AngularJS に基づいたシングルページ アプリケーションの構築

  • HTML 高度なグラフィックス テクノロジ

または私たちのチーム シリーズ:

  • HTML/JavaScript パフォーマンス最適化のヒント (このシリーズは、レスポンシブ デザインからカジュアル ゲームのパフォーマンス最適化まで、7 つのパートで構成されています)

  • 最新の Web プラットフォームのクイック スタート (HTML、CSS、および JS の基本)

  • HTML と JavaScript を使用してユニバーサル Windows アプリを開発し、すぐに開始できます (独自の JS を使用してアプリを構築します)

また、いくつかの無料ツール: Visual Studio Community、Azure Trial、および Mac、Linux 用のクロスブラウザー テスト ツールまたはWindows。

結論

ご覧のとおり、クロージャ スペース属性 (メカニズム) は、真にプライベートなデータを作成する優れた方法です。若干のメモリ消費量の増加(問題)が発生する可能性がありますが、私の意見では、これは非常に合理的です(この価格は、従来の方法と比較してより高いパフォーマンスの向上と交換できます)。

ちなみに、自分で試してみたい場合は、ここからコードをダウンロードできます。ここで、Azure Mobile Services に関する優れた記事「ハウツー」をお勧めします。

以上がJavaScript オブジェクトにプライベート メンバーを埋め込む方法のコード例 (図)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。