内容的栏目 * @param int $category 0列表 1频道 2单页 3外链 * @return array */ function category_list($forumlist, $model = 0, $display = 0, $category = 0) { if (empty($forumlist)) return NULL; static $cache = array(); $key = $model . '-' . $display . '-' . $category; if (isset($cache[$key])) return $cache[$key]; if ($display) { foreach ($forumlist as $k => $val) { if (1 == $val['display'] && 1 == $val['type'] && $val['category'] == $category) { $cache[$key][$k] = $val; } } } else { foreach ($forumlist as $k => $val) { if (1 == $val['type'] && $val['category'] == $category) { $cache[$key][$k] = $val; } } } return empty($cache[$key]) ? NULL : $cache[$key]; } /** * @param $forumlist 所有版块列表 不分模型 * @param int $display 0全部CMS栏目 1在首页和频道显示内容的栏目 * @param int $category 0列表 1频道 2单页 3外链 * @return array */ function category_list_show($forumlist, $display = 0, $category = 0) { if (empty($forumlist)) return NULL; static $cache = array(); $key = $display . '-' . $category; if (isset($cache[$key])) return $cache[$key]; if ($display) { foreach ($forumlist as $k => $val) { if (1 == $val['display'] && 1 == $val['type'] && $val['category'] == $category) { $cache[$key][$k] = $val; } } } else { foreach ($forumlist as $k => $val) { if (1 == $val['type'] && $val['category'] == $category) { $cache[$key][$k] = $val; } } } return empty($cache[$key]) ? NULL : $cache[$key]; } /** * @param $forumlist 所有版块列表 * @return mixed BBS栏目数据(仅列表) 尚未开放bbs频道功能 */ function forum_list($forumlist) { if (empty($forumlist)) return array(); static $cache = array(); if (isset($cache['bbs_forum_list'])) return $cache['bbs_forum_list']; $cache['bbs_forum_list'] = array(); foreach ($forumlist as $_fid => $_forum) { if ($_forum['type']) continue; $cache['bbs_forum_list'][$_fid] = $_forum; } return $cache['bbs_forum_list']; } // 导航显示的版块 function nav_list($forumlist) { if (empty($forumlist)) return NULL; static $cache = array(); if (isset($cache['nav_list'])) return $cache['nav_list']; foreach ($forumlist as $fid => $forum) { if (0 == $forum['nav_display']) { unset($forumlist[$fid]); } } return $cache['nav_list'] = $forumlist; } ?>JavaScript - Accessing Private Instance Variable from Prototype Method - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript - Accessing Private Instance Variable from Prototype Method - Stack Overflow

programmeradmin0浏览0评论

[Yes, I have read several answers to similar questions, but didn't really get the answer I'm looking for, so I'm going to ask my question anyway.]

In the code below, how can I place the methods setSecret and tellSecret in Secret's prototype while still maintaining access to the private instance variable _secret, and also producing the same output?

I tried this (see jsbin) which placed the methods in the prototype, but changed the output.

function Secret() {

    // ===== private =====

    var _secret;

    // ===== public =====

    this.setSecret = function (secret) {
        _secret = secret;
    };

    this.tellSecret = function () {
        console.log(_secret);
    };
}

var secretA = new Secret();
var secretB = new Secret();

secretA.setSecret("AAA");
secretB.setSecret("BBB");

setTimeout(function () {
    console.log("Secret A");
    secretA.tellSecret();

    console.log("Secret B");
    secretB.tellSecret();
}, 1000);


// ===== output =====

Secret A
AAA
Secret B
BBB

[Yes, I have read several answers to similar questions, but didn't really get the answer I'm looking for, so I'm going to ask my question anyway.]

In the code below, how can I place the methods setSecret and tellSecret in Secret's prototype while still maintaining access to the private instance variable _secret, and also producing the same output?

I tried this (see jsbin) which placed the methods in the prototype, but changed the output.

function Secret() {

    // ===== private =====

    var _secret;

    // ===== public =====

    this.setSecret = function (secret) {
        _secret = secret;
    };

    this.tellSecret = function () {
        console.log(_secret);
    };
}

var secretA = new Secret();
var secretB = new Secret();

secretA.setSecret("AAA");
secretB.setSecret("BBB");

setTimeout(function () {
    console.log("Secret A");
    secretA.tellSecret();

    console.log("Secret B");
    secretB.tellSecret();
}, 1000);


// ===== output =====

Secret A
AAA
Secret B
BBB
Share Improve this question edited Feb 3, 2014 at 8:06 RBR asked Feb 3, 2014 at 6:28 RBRRBR 9993 gold badges13 silver badges24 bronze badges 9
  • 2 You can't. There are no "private instance variables" in JavaScript. _secret is a local variable, so only functions defined inside the constructor can access it. End of story. – Felix Kling Commented Feb 3, 2014 at 6:38
  • possible duplicate of javascript - accessing private member variables from prototype-defined functions – Felix Kling Commented Feb 3, 2014 at 6:39
  • Felix, by "private instance variables" I mean in closure scope. See jsbin link above- I am able to access _secret from prototype methods, but the output changes, i.e. the second instance's secret overwrites the first instance's secret. – RBR Commented Feb 3, 2014 at 7:31
  • I know what you mean. But it's just not possible, at least not with current implementations. There are a couple of other related questions: stackoverflow./questions/17220653/…, stackoverflow./questions/9572029/…, stackoverflow./questions/8580540/…, stackoverflow./questions/6307684/…, – Felix Kling Commented Feb 3, 2014 at 7:44
  • What is just not possible? Please be specific. – RBR Commented Feb 3, 2014 at 8:11
 |  Show 4 more ments

4 Answers 4

Reset to default 6

Simply put, you shouldn't use private variables with prototype methods. Trying to mix the two requires awful workarounds, and there are better alternatives.
Here's an explanation why. (This is an excerpt from a similar answer: https://stackoverflow./a/21522742/272072)

Prototypal Methods

In JavaScript, prototype methods allows multiple instances to share a prototype method, rather than each instance having its own method.
The drawback is that this is the only thing that's different each time the prototype method is called.
Therefore, any "private" fields must be accessible through this, which means they must also be publicly accessible. So, the best we can do is to stick to naming conventions for _private fields.

Mixing with Private Variables

When you use a closure to create a private variable, you cannot access it from a prototypal method unless it's exposed through the this variable. Most solutions, therefore, just expose the variable through method, which means that you're exposing it publicly one way or another.

Just use conventions for _private fields

So, I think using _private fields makes the most sense, even though they're still public. It makes debugging easier, provides transparency, could improve performance, and so that's what I usually use.
Stick to conventions for _private fields and everything goes great.
And I just don't understand why JS developers try SO hard to make fields truly private.

this one is related to Alon's answer, but by implementing a WeakMap, doesn't reveal an identifying index and won't accumulate un-used objects. While a better solution in terms of efficiency, it's not as good an answer in terms of patibility. WeakMaps are supported in FireFox and Chrome and Node.JS, so i feel they are worth mentioning.

see https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap for more info.

var Secret = (function(){

   var secrets=new WeakMap();

  function Secret() {

    // ===== private =====

    secrets.set(this, null);

   // ===== public =====

   }

    Secret.prototype.setSecret = function (secret) {
       secrets.set(this, secret);
    };

    Secret.prototype.tellSecret = function () {
        console.log(secrets.get(this));
    };


   return Secret;

}());


var secretA = new Secret();
var secretB = new Secret();

secretA.setSecret("AAA");
secretB.setSecret("BBB");

setTimeout(function () {
    console.log("Secret A", secretA  );
    secretA.tellSecret();

    console.log("Secret B", secretB );
    secretB.tellSecret();
}, 1000);

This is an incredibly ugly solution, and you probably shouldn't use it, but it works. Based on this answer.

var Secret = (function () {
    var instance = 0,
        p = [];

    function Secret() {
        this.i = instance++;
        p[this.i] = {};
        p[this.i]._secret = null;
    }

    Secret.prototype.setSecret = function (secret) {
        p[this.i]._secret = secret;
    };

    Secret.prototype.tellSecret = function () {
        console.log(p[this.i]._secret);
    };

    return Secret;
})();

var secret = new Secret();
secret.setSecret("A");

var secret2 = new Secret();
secret2.setSecret("B");

console.log(secret._secret)  // => undefined

secret.tellSecret()          // => A
secret2.tellSecret()         // => B

Try this, and tell me if it's what you search.
To make more interesting the snippet I added more 2 private properties to your object Secret
(Note that all your private vars are really private)

function Secret() {
  // ===== private =====	
  var _properties = { secret:null, secret2:null, secret3:null } // <-- Put all yours properties here

  // ===== public =====
  this.getset = function(PROP, V) { 
        if(typeof V !== "undefined") _properties[PROP]=V; return _properties[PROP]; 
  }
}

 // Create GETTER & SETTER for each of yours properties
 MAKE_GET_SET(Secret, "secret", true, true);    // get and set 
 MAKE_GET_SET(Secret, "secret2", true, true);   // only set
 MAKE_GET_SET(Secret, "secret3", true, false);  // only get


/* === "Magic function" ;-) to create new properties's GETTER & SETTER ============= */
function MAKE_GET_SET(OBJ, PROPNAME, makeGET /* boolean */, makeSET /* boolean */) {  
      Object.defineProperty( OBJ.prototype, PROPNAME, { 
        get: function() { return makeGET ? this.getset(PROPNAME) : null; }, 
        set: function(V) { if(makeSET) this.getset(PROPNAME,V); }, 
        enumerable: true
      } );
} 
/* ================================================================================= */

var secretA = new Secret();
var secretB = new Secret();

secretA.secret = "AAA";  // <-- here use setter
secretB.secret = "BBB";  // <-- here use setter

setTimeout(function () {
    console.log("Secret A: "+secretA.secret);  // <-- here use getter
    console.log("Secret B: "+secretB.secret);  // <-- here use getter
}, 1000);

/* ===== output =====

Secret A: AAA
Secret B: BBB

 ===== output ===== */

发布评论

评论列表(0)

  1. 暂无评论