1

JavaScriptでは、次のようなトップレベルのオブジェクトを使用して「ライブラリ」または機能のコレクションを書き始めることができます。

window.Lib = (function()
{
    return {

        // Define Lib here.
        //

    };

})();

Libまた、それに関連するオブジェクトを作成するのに役立ついくつかの関数を追加することもできます。

window.Lib = (function()
{
    return {

        ObjectA: function()
        {
            var _a = 5;

            return {

                getA: function(){ return _a; }

            };

        },


        ObjectB: function()
        {
            var _b = 2;
            var _c = 1;

            return {

                getB: function(){ return _b; }

            };

        }

    };

})();

これは次のように使用されます:

var thing = Lib.ObjectA();
var thing2 = Lib.ObjectA();
var thing3 = Lib.ObjectB();

そして、上記で作成された各メソッド内のメソッドを使用して、次の範囲内で定義された、または次の範囲内で_a定義されたの値を取得できます。ObjectA()_bObjectB()

alert(thing.getA()); // 5
alert(thing3.getB()); // 2

私が達成したいのはこれです:

プロパティ_c(内で定義されているObjectB())にアクセスしたいが、スコープ内でのみLibアクセスしたいとします。どうすればそれについて行くことができますか?つまり、によって返されるオブジェクト内で定義した関数内でプロパティを読み取り可能にしLib()たいのですが、それらの値をその外に公開したくありません。

コード例:

window.Lib = (function()
{
    return {

        ObjectA: function(){ ... },
        ObjectB: function(){ ... },

        assess: function(obj)
        {
            // Somehow get _c here.
            alert( obj.getInternalC() );
        }

    };

})();

これは次のように機能します:

var thing = Lib.ObjectB();
alert( thing.getInternalC() ) // error | null | no method named .getInternalC()

Lib.assess(thing); // 1

これが理にかなっていることを願っています。

4

2 に答える 2

2

インスタンスごとに保護されたプロパティが必要ですか? つまりObjectAObjectB、 などによって作成されたインスタンスのプロパティですが、ライブラリ内のコードからのみアクセスでき、ライブラリ外のコードからはアクセスできないものですか?

現在、JavaScript ではこれを適切に行うことはできませんが、次のバージョンではプライベート ネーム オブジェクトを使用して行うことができます。(ただし、ES5 で現在実行できる同様のことについては、以下の「ほぼ実行中」を参照してください。)

次のように、インスタンスごとのプロパティでLibはなく、内のすべてのコードで共有されるデータを簡単に作成できます。

window.Lib = (function()
{
    var sharedData;

    // ...
})();

そこに定義されているすべての関数 ( yourObjectAなど) は、その 1 つのsharedData変数にアクセスでき、外部からは完全にアクセスできません。しかし、それはインスタンスごとではなくObjectAObjectB、 などによって作成された各オブジェクトは独自のコピーを取得しません。

ほとんどやってる

コードがES5を使用する環境で実行される場合 (つまり、「モダン」に IE8 以前が含まれない最新のブラウザー) 、. これは、プライベートな名前オブジェクトが ES.next でどのように機能するかに似ていますが、完全にプライベートではありません:Object.defineProperty

実例| ソース

window.Lib = (function() {
    // Get a random name for our "c" property
    var c = "__c" + Math.round(Math.random() * 1000000);

    // Return our library functions
    return {

        ObjectA: function() {
            // Create an object with a couple of public proprties:
            var obj = {
                pub1: "I'm a public property",
                pub2: "So am I"
            };

            // Add our obscured "c" property to it, make sure it's
            // non-enumerable (doesn't show up in for-in loops)
            Object.defineProperty(obj, c, {
                enumerable: false,  // false is actually the default value, just emphasizing
                writable:   true,
                value:      "I'm an obscured property"
            });

            // Return it
            return obj;
        },

        ObjectB: function(){ /* ... */ },

        assess: function(obj) {
            // Here, we access the property using the `c` variable, which
            // contains the property name. In JavaScript, you can access
            // properties either using dotted notation and a literal
            // (`foo.propName`), or using bracketed notation and a string
            // (`foo["propName"]`). Here we're using bracketed notation,
            // and our `c` string, which has the actual property name.
            display( obj[c] );
        },


        alter: function(obj, value) {
            // Similarly, we can change the value with code that has
            // access to the `c` variable
            obj[c] = value;
        }
    };
})();

そして、次のように使用します。

// Create our object
var o = Lib.ObjectA();

// Play with it
display("pub1: " + o.pub1); // displays "pub1: I'm a public property"
display("c: " + o.c);       // displays "c: undefined" since `o` has no property called `c`
Lib.assess(o);              // displays "I'm an obscured property"

// Note that our obscured property doesn't show up in for-in loops or Object.keys:
var propName, propNames = [];
for (propName in o) {
    propNames.push(propName);
}
display("propNames: " + propNames.join(","));
display("Object.keys: " + Object.keys(o).join(","));

// Our Lib code can modify the property
Lib.alter(o, "Updated obscured property");
Lib.assess(o);

によって返されるオブジェクトにLib.ObjectAは、ロードされるたびに名前が変わるプロパティがあり、Lib列挙できません (for-inループには表示されません)。それを理解する唯一の方法は、その名前を知ることです (これも、Libページが読み込まれるたびに、作成されるたびに変わります)。内部のコードは、すべてのコードで共有される変数にあるLibため、プロパティ名が何であるかを認識しています。括弧付き表記と文字列を使用してプロパティにアクセスできるため、 を使用してプロパティにアクセスできます。cLibinstance[c]

これらがかなりよく隠されていることがわかります。外部のコードLibは、オブジェクト内のプロパティを列挙するときに隠蔽されたプロパティを認識せず、割り当てた半ランダムな名前がわからないため、プロパティを見つけることができません。もちろん、デバッガーを使用して検査することで見つけることができますが、デバッガーは多くのことを行うことができます。

実際、これは ES.next でプライベート プロパティがどのように機能するかを示しています。ただしc、これは文字列ではなく、プライベートな名前オブジェクトになります。

于 2012-12-05T13:12:39.937 に答える
1

まあ、あなたは「ちょうど」のContext内でこれらの変数を宣言する必要がありますLib

window.Lib = (function()
{
    var _c = 42;   

    return {
    };
});

その疑似コンストラクター関数の自動呼び出しを削除したことに注意してください。つまり、複数のインスタンスに対して複数の呼び出しを作成する必要があり、それぞれに固有の値のセットがあります。Lib()

var inst1 = Lib(),
    inst2 = Lib();

すべての子コンテキスト (関数) からの共有アクセスのみが必要な場合は、既に行っているのと同じパターンを使用できます (上記のようにvar宣言を親コンテキストに移動する場合のみ)。

于 2012-12-05T13:11:37.253 に答える