簡體   English   中英

具有私有/公共方法的Javascript模塊模式

[英]Javascript Module pattern with private/public methods

我被要求制作一個Javascript模塊來充當瀏覽器事件的計數器,並且無法修改實際的計數事件(私有方法)。

var CountingLogger = (function() {

var secret ={};
var uid = 0;
function CountingLogger(events) {
    secret[this.id = uid++] = {};
    // Store private stuff in the secret container
    // instead of on `this`.
    secret[this.id].events = events || 0;
}

CountingLogger.prototype.log = function (eventName) {
    alert(secret[this.id].events[eventName]);
    if (typeof secret[this.id].events[eventName] === 'undefined') {
        secret[this.id].events[eventName] = 0;
    }
    secret[this.id].events[eventName]++;
    var count = secret[this.id].events[eventName];
    $('#logContents').append('<li>' + eventName + ': ' +  count + '</li>');
};

return CountingLogger;
}());

在main.js中,我定義了: var logger = new CountingLogger(); 然后調用logger.log('EventName');

並且應在回調中顯示一個計數器“ EventName” + Counter,因此事件名稱:1,SecondEvent:4 ...但在日志中始終顯示未定義的“ WhateverEvent”。 任何人都可以知道如何解決嗎? 問候

您不希望擁有自己級別的secrets 正如Bergi所說 ,這是內存泄漏。

(注意:當我在下面說“真正私有”時,請記住,如果有人正在使用調試器,則沒有什么是真正私有的。下面的“真正私有”只是使任何人都不可能編寫使用對該對象的引用來獲取或修改的代碼。私人數據。)

ES7將擁有真正的私有財產。 在此之前,您基本上有三個選擇:

  1. 真正的私有數據,通過對構造函數的調用的閉包來保存

  2. 通過屬性命名約定“保持雙手”屬性

  3. 很難使用的屬性,雖然不是私有的,但很難根據它們編寫代碼

真正的私人數據

如果您希望按實例獲取真正的私有信息,那么標准的方法是在構造函數中使用變量,並在構造函數中定義需要該私有數據的方法:

function Foo() {
    var secret = Math.floor(Math.random() * 100);
    this.iWillTellYouASecret = function() {
        console.log("The secret is " + secret);
    };
}
Foo.prototype.iDoNotKnowTheSecret = function() {
    console.log("I don't know the secret");
};

是的,這意味着將為每個實例創建一個新的iWillTellYouASecret函數,但是當將該實例從內存中刪除時,該函數(和秘密)也會被回收 ,並且不錯的JavaScript引擎可以在這些函數對象之間重用該函數的代碼

“放開手”屬性

但是在大多數情況下,您不需要真正的私人信息,只需說“讓我遠離您”的信息。 JavaScript中的約定是以_開頭的屬性。 是的,這意味着可以訪問實例的代碼可以使用或更改該屬性的值,但是在大多數具有“真正私有”屬性的語言(例如Java)中,通過反射實際上也是如此。

很難使用的屬性

如果您想讓試圖使用您的私人數據的人生活變得更艱難,可以使用我的一篇舊博客文章中的技巧*(當ES6通過Name對象具有真正的隱私時便寫回了該Name ;從那時起, Name已經變成了Symbol ,並且不再用於隱私):

首先,創建一個Name psuedo-class:

var Name = function() {
    var used = {};

    function Name() {
        var length, str;

        do {
            length = 5 + Math.floor(Math.random() * 10);
            str = "_";
            while (length--) {
                str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
            }
        }
        while (used[str]);
        used[str] = true;
        return new String(str); // Since this is called via `new`, we have to return an object to override the default
    }

    return Name;
}();

然后,將此模式用於私有實例屬性:

// Nearly-private properties
var Foo = (function() {
    // Create a random string as our private property key
    var nifty = new Name();

    // Our constructor    
    function Foo() {
        // We can just assign here as normal
        this[nifty] = 42;
    }

    // ***On ES5, make the property non-enumerable
    // (that's the default for properties created with
    // Object.defineProperty)
    if (Object.defineProperty) { // Only needed for ES3-compatibility
        Object.defineProperty(Foo.prototype, nifty, {
            writable: true
        });
    }
    // ***End change

    // Methods shared by all Foo instances
    Foo.prototype.method1 = function() {
        // This method has access to `nifty`, because it
        // closes over the private key
        console.log("Truly private nifty info: " + this[nifty]);
    };
    Foo.prototype.method2 = function() {
        // Also has access, for the same reason
        console.log("Truly private nifty info: " + this[nifty]);
    };

    return Foo;
})();

var f = new Foo();
f.method1(); // Can use nifty!
f.method2(); // Can too! :-)
// Both `method1` and `method2` are *reused* by all `Foo` objects

現在,每次運行代碼時,私有財產的名稱都會不同。

這仍然不是私人的 很難找到。

javascript中的私有方法只能用於封裝目的。

不可能阻止某人操縱javascript中的任何方法。

用戶可以簡單地在您的私有方法上放置一個調試點,然后開始操縱您的私有邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM