如何创建Prototype函数可访问的私有变量?

时间:2011-06-10 14:22:21

标签: javascript prototypal-inheritance

我试图更深入地抓住原型继承和类创建(我知道,还有其他方法,但为了这个目的,我试图掌握原型。)我的问题是:使用以下代码示例,是否有一种方法可以在TreeFruit内部创建私有变量,这些变量不会随函数返回,但仍可由原型函数genus访问,并且bulk

var Tree = function ( name, size ) { 
    this.name = name;
    this.size = size;
};

Tree.prototype.genus = function(){
    return ((typeof this.name !== 'undefined') ? this.name : 'Hybridicus Maximus');
};
Tree.prototype.bulk = function(){
    return ((typeof this.size !== 'undefined') ? this.size : '8') + ' ft';
};


var Fruit = function( name, size ) { 
    this.name = name;
    this.size = size;
};

Fruit.prototype = new Tree();
// Fruit.prototype = Tree.prototype; -- I know this can be used, too.

Fruit.prototype.bulk =  function(){
    return ((typeof this.size !== 'undefined') ? Math.floor(this.size / 2) : '4') + ' lbs';
};

var pine = new Tree('Pine', 9);
var apple = new Fruit('Apple', 6);

console.log(pine.genus(), pine.bulk()); // Outputs: "Pine 9 ft"
console.log(apple.genus(), apple.bulk()); // Outputs: "Apple 3 lbs"

编辑:我尝试将this.namethis.size替换为可在原型函数中访问的私有变量。抱歉缺乏清晰度!

4 个答案:

答案 0 :(得分:13)

是。你可以这样做:

(function() {
  var private = "hi";

  Tree.prototype.genus = function(){
    return ((typeof this.name !== 'undefined') ? this.name : 'Hybridicus Maximus');
  };
  Tree.prototype.bulk = function(){
    return ((typeof this.size !== 'undefined') ? this.size : '8') + ' ft';
  };
})();

现在,它将提供这些函数可以看到的私有变量,但它将是一个私有的“类”变量 - 换句话说,所有实例将共享相同的变量。如果你想要每个实例的私有变量,你必须在构造函数(或“init”方法,或其他)中这样做,这意味着必须在那里创建共享这些私有的方法。 (你当然可以在原型上放置一个函数,在构造时创建实例方法。)

编辑 - 你可以做的一件事是使用这样的技术来构建像jQuery的“.data()”这样的机制,这样你就有了一个充当地方的类变量保持每个实例的值。它有点笨重,但它是可行的。

答案 1 :(得分:2)

这是我在关于Classes, Private Members, & Prototypal Inheritance in JavaScript的博文中所写的内容。基本上你想创建一个对每个对象都唯一的私有变量访问器函数,然后让那些原型方法调用那个私有访问器函数,为它提供只在闭包中可用的密钥:

(function(_) {
  Tree = function ( name, size ) { 
    var hidden = {
      name: name,
      size: size
    };
    this._ = function($) {
      return _ === $ && hidden;
    };
  };

  Tree.prototype.genus = function(){
    return ((typeof this._(_).name !== 'undefined') ? this._(_).name : 'Hybridicus Maximus');
  };
  Tree.prototype.bulk = function(){
    return ((typeof this._(_).size !== 'undefined') ? this._(_).size : '8') + ' ft';
  };

  Fruit = function( name, size ) { 
    Tree.apply(this, arguments);
  };
  Fruit.prototype = new Tree();
  // Fruit.prototype = Tree.prototype; -- I know this can be used, too.

  Fruit.prototype.bulk =  function(){
    return ((typeof this._(_).size !== 'undefined') ? Math.floor(this._(_).size / 2) : '4') + ' lbs';
  };
})({});



var pine = new Tree('Pine', 9);
var apple = new Fruit('Apple', 6);

console.log(pine.genus(), pine.bulk()); // Outputs: "Pine 9 ft"
console.log(apple.genus(), apple.bulk()); // Outputs: "Apple 3 lbs"

console.log(pine._(), pine._({})); // Outputs: "false false" because outside of closure

您会注意到最后一行显示私有变量在闭包之外是不可访问的,因此除非由访问者函数提供,否则无法通过第三方代码检索。

答案 2 :(得分:0)

可以像这样轻松实现

function SharedPrivate(){
  var private = "secret";
  this.constructor.prototype.getP = function(){return private}
  this.constructor.prototype.setP = function(v){ private = v;}
}

var o1 = new SharedPrivate();
var o2 = new SharedPrivate();

console.log(o1.getP()); // secret
console.log(o2.getP()); // secret
o1.setP("Pentax Full Frame K1 is on sale..!");
console.log(o1.getP()); // Pentax Full Frame K1 is on sale..!
console.log(o2.getP()); // Pentax Full Frame K1 is on sale..!
o2.setP("And it's only for $1,795._");
console.log(o1.getP()); // And it's only for $1,795._

显然,关键点是通过利用闭包创建到私有变量的访问路由,然后在要创建的对象之间共享此访问点。利用接入点作为要为自然共享创建的对象的原型是理想的情况。因此,通过利用工厂模式和Object.create()可以实现相同的功能,如下所示;

function SharedPrivate(){
var priv = "secret";
return {gp : function(){return priv},
        sp : function(v){priv = v}
       }
}
sharedProto = SharedPrivate(); // priv is now under closure to be shared
var p1 = Object.create(sharedProto); // sharedProto becomes o1.__proto__
var p2 = Object.create(sharedProto); // sharedProto becomes o2.__proto__

JavaScript原型结构是金色的!!

答案 3 :(得分:-1)

我根据您的问题标题而不是您提供的内容编写此内容。我在这里有同样的问题。

var Tree = function(){

    var outprivatename = "bigsecret"

    var Tre = function(nickname){
        var privatename = "secret that no one should know" 
        this.nickname = nickname
        outprivatename = outprivatename + "-->" + nickname
        this.deepsecret=function(){return privatename + "---" + nickname}
    }

    Tre.prototype.getname=function(){
        console.log(outprivatename+'-----'+this.nickname)
        // console.log(privatename)
      return this.nickname
    }
    return Tre

}
//case one: each has unique closure; `outprivatename` is different for them
var pine = new (Tree())('pine')
var apple = new (Tree())('apple')
pine.getname() //bigsecret-->pine-----pine
apple.getname() //bigsecret-->apple-----apple
console.log(pine.deepsecret()) //secret that no one should know---pine
console.log(apple.deepsecret()) //secret that no one should know---apple

//case one: two share one closure; `outprivatename` is same for both
var Hybrid = Tree()
var hybrid1 = new Hybrid("pinapple1")
var hybrid2 = new Hybrid("pinapple2")

hybrid1.getname() //bigsecret-->pinapple1-->pinapple2-----pinapple1
hybrid2.getname() //bigsecret-->pinapple1-->pinapple2-----pinapple2
console.log(hybrid1.deepsecret()) //secret that no one should know---pinapple1
console.log(hybrid2.deepsecret()) //secret that no one should know---pinapple2

基本上Tree函数为其中的构造函数Tre提供了一个闭包。您可以使用privatename之外但在匿名函数Tre内的那个,而不是使用最深的Tree