如何在构造函数中设置javascript私有变量?
假设我有一个名为如何在构造函数中设置javascript私有变量?,javascript,oop,scope,Javascript,Oop,Scope,假设我有一个名为Foo的javascript函数/类,它有一个名为bar的属性。我希望在实例化类时提供bar的值,例如: var myFoo = new Foo(5); 将myFoo.bar设置为5 如果我将bar设置为公共变量,则此操作有效,例如: function Foo(bar) { this.bar = bar; } 但如果我想保密,例如: function Foo(bar) { var bar; } 那么我如何设置私有变量bar的值,使其可用于foo的所有内部函数?
Foo
的javascript函数/类,它有一个名为bar
的属性。我希望在实例化类时提供bar
的值,例如:
var myFoo = new Foo(5);
将myFoo.bar
设置为5
如果我将bar
设置为公共变量,则此操作有效,例如:
function Foo(bar)
{
this.bar = bar;
}
但如果我想保密,例如:
function Foo(bar)
{
var bar;
}
那么我如何设置私有变量
bar
的值,使其可用于foo
的所有内部函数?关于javascript中私有和受保护访问的最佳教程如下:
您必须将需要访问私有变量的所有函数放入构造函数中:
function Foo(bar)
{
//bar is inside a closure now, only these functions can access it
this.setBar = function() {bar = 5;}
this.getBar = function() {return bar;}
//Other functions
}
var myFoo = new Foo(5);
myFoo.bar; //Undefined, cannot access variable closure
myFoo.getBar(); //Works, returns 5
我最近遇到了一个类似的问题,但我也想使用访问器属性。下面是一个Foo(Bar)示例,它基于我提出的解决方案。这个例子很简单,但在使用更复杂的get/set函数时可以很容易地进行扩展
function Foo(Bar){
Object.defineProperty(this,"bar",{get:function(){return Bar},set:function(val){Bar=val}});
}
x=new Foo(3);
y=x.bar; //3
x.bar++; //x.bar==4
我能想到的一种方法是使用一个指定给名称并返回新对象的闭包。您可以通过调用闭包将任何参数传递给构造函数。最终的结果是如下所示:
var fooFactory = function (a, b) {
var c = 5,
d = 6,
foo;
foo = function (a, b) {
this.a = a;
this.b = b;
this.bar();
}
foo.prototype.bar = function () {
//do something with c and d
this.c = c + d;
}
foo.prototype.getC = function () {
return c;
}
foo.prototype.getD = function () {
return d;
}
return new foo(a, b);
};
这样,a和b总是唯一声明的。然后,您可以这样构造对象:
var obj = fooFactory(1, 2);
//obj contains new object: { a: 1, b: 2, c: 11 }
console.log(obj.getC());
//returns 5
如果您愿意使用ES2015课程 使用ESNext,您可以这样使用:
class-Foo{
#条='';
构造函数(val){
这个#bar=val;
}
其他fn(){
console.log(这个#条);
}
}
在Foo类之外,无法访问私有字段#栏。在ES6+术语中,正确的方法如中所示。然而,如果出于某种原因,您希望坚持使用好的旧构造函数,那么它可以像这样实现
function Foo(val){
function Construct(){};
Construct.prototype = { set bar(_){} // you may throw an error here
, get bar(){return val;}
};
return new Construct();
};
所以这里发生了两件事
Foo
的实例setter
访问私有变量时,您可以随意抛出错误,也可以不抛出错误function Foo(val){
Object.defineProperty(this,"bar",{ set: function(){}
, get: function(){return val;}
});
};
不管是谁否决了这个,你能解释为什么吗?在我看来这是正确的+1I没有,但在许多语言中,能够使用相同的参数名而不是像“a”这样的名称是很好的。也就是说,拥有一个名为'bar'的参数并将其分配给一个名为'bar'@gabriellamas的变量-我想您不理解这段代码的意义。如果
bar
是真正私有的,因此无法从外部访问(这是OP要求的),那么它必须声明为我所做的。而且,如果您像我所做的那样声明bar
,则无法从原型上定义的方法访问它。您必须在bar
的范围内定义函数。是的,如果要实例化大量的Foo()
对象,那么它就没有那么高效了,但这是一种使bar私有化的方法,这正是我们要问的问题。请删除你的否决票。@Gabriellamas-这种方法没有不好的做法。这只是一种权衡。为了实现隐私,在创建对象时,您会接受一个微小的性能影响。创建对象后,该对象的性能非常好。原型机在那里是为了方便。你没有理由用它来实现你的目标。如果您要创建大量的Foo()
对象,并且性能至关重要,那么这将是一个糟糕的权衡。但是,如果您只是创建了一对,或者此方法的性能非常好,并且您想要可变的隐私,那么此方法是一个很好的实践。@Gabriellamas-此获取隐私的方法不是黑客。它使用该语言支持的特性(闭包)来解决一个不是最初设计到该语言中的问题。这不是黑客攻击-这是一个创造性的解决方案,如果需要它提供的功能,那么使用它绝对没有错。FWIW,你不能拥有真正的私有变量并利用原型。我个人会提供,而不是使代码更复杂…@FelixKing这是怎么回事?+1个很好的例子。有一件事我还很困惑。是什么使bar
invar bar=b
persistent?嗨@Gary,希望我能解释一下:每次构造new Foo
时,都会在该Foo
构造函数的功能范围内创建一个新的bar
。只要Foo
在内存中存在,bar
就会在内存中存在(或者对Foo
中的任何函数的引用,这些函数都可以访问bar
。正如Foo
的每个实例都有自己的setBar
和alertBar
,它有自己的bar
,事实上,它也有自己的b
。请参阅这个JSFiddle以获得更简洁的版本:@Gary Javascript区分大小写。Bar和Bar是两个独立的属性。Bar是Foo的私有属性,而Bar是提供对Bar访问的公共属性。这与公认的答案是一样的。我投票赞成这个答案,但后来我意识到它是错误的;每次“fooFactory”调用时,所有原型的方法都是从头开始重新创建的。因此,与直接向对象添加方法相比,它没有任何优势,这只会导致混乱。
function Foo(val){
function Construct(){};
Construct.prototype = { set bar(_){} // you may throw an error here
, get bar(){return val;}
};
return new Construct();
};
function Foo(val){
Object.defineProperty(this,"bar",{ set: function(){}
, get: function(){return val;}
});
};