问题
I'm trying to get a deeper hold on prototypal inheritance and class creation (I know, there are other ways, but for the purpose of this I'm trying to grasp prototypes.) My question is: Using the following code example, is there a way to create private variables inside of Tree
and Fruit
that will not be returned with the function, but is still accessible to the prototype functions genus
and 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"
EDIT: I'm trying to replace this.name
and this.size
with private variables that can be accessed in the prototype functions. Sorry for the lack of clarity!
回答1:
Yes. You can do this:
(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';
};
})();
Now, that'll provide a private variable that those functions can see, but it'll be a private "class" variable - all instances will share the same variable, in other words. If you want a private variable per instance, you have to do that in the constructor (or "init" method, or whatever), meaning the methods that share those privates would also have to be created there. (You could of course put a function on the prototype that would create the instance methods at construction time.)
edit — One thing you could do is use a technique like this to build a mechanism like jQuery's ".data()", so that you'd have a class variable that acts as a place to keep per-instance values. It'd be kind-of clunky, but it'd be workable.
回答2:
This is what I wrote about in a blog post about Classes, Private Members, & Prototypal Inheritance in JavaScript. Basically you want to create a private variable accessor function unique to every object and then have those prototype methods call that private accessor function, supplying it with the key that is only available within the closure:
(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
You will notice that the last line shows that private variables are not accessible outside of the closure and thusly can't be retrieved by third-party code unless made available by an accessor function.
回答3:
It can be easily achieved like this
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._
Obviously the key point is to create an access route to a private variable by utilizing a closure and then sharing this access point among the objects to be created. Utilizing the access point as a prototype of the objects to be created for natural sharing is the ideal case. Accordingly the same functionality can be achieved by utilizing the factory pattern and Object.create()
as follows;
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 prototypical structure is golden..!
回答4:
i made up this based on your title of question, not the content you gave. i had the same question here.
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
basically the Tree
function provided a closure for the constructor Tre
inside of it. Instead of using the deepest privatename
, you can use the one that's outside of Tre
but inside of the anonymous function Tree
.
来源:https://stackoverflow.com/questions/6307684/how-to-create-private-variable-accessible-to-prototype-function