JavaScript私有变量的解决方案?
我问这个问题是因为我想我找到了一个JavaScript问题的解决方案,我想知道我是否偏离了底线。我希望在这里问这个问题是恰当的 我相信您知道,JavaScript没有私有属性。此问题通常使用两种模式之一解决 第一种方法是使用闭包在构造函数内创建特权方法,并使用JavaScript私有变量的解决方案?,javascript,private-members,Javascript,Private Members,我问这个问题是因为我想我找到了一个JavaScript问题的解决方案,我想知道我是否偏离了底线。我希望在这里问这个问题是恰当的 我相信您知道,JavaScript没有私有属性。此问题通常使用两种模式之一解决 第一种方法是使用闭包在构造函数内创建特权方法,并使用this关键字将它们绑定到对象。这就是技术。下面是一个例子: function Person(name) { function getName() { return name; } this.who
this
关键字将它们绑定到对象。这就是技术。下面是一个例子:
function Person(name) {
function getName() {
return name;
}
this.who = getName;
}
这种模式的问题在于存在污染全局名称空间的巨大危险:
var me = Person("Karl"); // Oops! no "new"
me.who(); // TypeError: Cannot read property 'who' of undefined
who(); // "Karl" - "who" is in global namespace!
第二种解决方案是使用。您将特权方法绑定到一个新对象,而不是绑定到this
:
function Person(name) {
function getName() {
return name;
}
return {
who: getName
}
}
var me = Person("Karl"); // No "new," but that's OK
me.who(); // "Karl"
who(); // TypeError: undefined is not a function
该模式的问题在于对象没有Person的原型链。因此,您无法正确检查其类型,也无法使用构造函数的原型扩展对象:
console.log(me instanceof Person); // "false"
Person.prototype.what = function() {
return this.constructor.name + ": " + this.who();
}
me.what(); // TypeError: undefined is not a function
我找到了解决这个问题的办法。使用具有Person原型链的临时构造函数,并返回使用临时构造函数构造的对象:
function Person(name) {
function getName() {
return name;
}
// Temporary constructor
function F() {
this.who = getName;
}
F.prototype = Person.prototype;
return new F();
}
// Can't pollute the global namespace
var me = Person("Karl");
me.who(); // "Karl"
who(); // TypeError: undefined is not a function
// Proper prototype chain: correct type checking, extensible
console.log(me instanceof Person); // "true"
Person.prototype.what = function() {
return this.constructor.name + ": " + this.who();
}
me.what(); // "Person: Karl"
关于此解决方案,我有几个相关问题:
我对你的问题没有答案,但有一个建议可以用一种更简单的方式解决你的所有问题:
function Person(name) {
"use strict";
if (!this) return new Person(name);
function getName() {
return name;
}
this.who = getName;
}
Person.prototype.what = function() {
return this.constructor.name + ": " + this.who();
}
适用于所有浏览器的替代方案
function Person(name) {
if (!(this instanceof Person)) return new Person(name);
function getName() {
return name;
}
this.who = getName;
}
Person.prototype.what = function() {
return this.constructor.name + ": " + this.who();
}
这种模式的问题是有污染全局名称空间的巨大危险:“这不是该模式的问题,而是所有“正常”构造函数的“问题”。如果这正是您所担心的,那么一个简单的解决方案就是做一个
instanceof
检查:If(!(this instanceof Person)){return new Person(name);}
。我个人认为,试图实现“私有财产”是不值得的努力和缺点。我们很快就会得到Symbol
s,使用它应该会更容易。“this.who=getname
”会将`who()添加到全局命名空间中吗?真的吗?@GolezTrol:是的,确实会。如果调用该函数时没有“new”关键字,则该函数不是构造函数,此
绑定到全局对象。@FelixKling:您的解决方案似乎非常简单,这让我质疑为什么在我读过的JavaScript书籍中没有遇到它。您是否确定instanceof
运算符在构造函数中有效(即原型链已绑定)?如果你的函数被称为“超级构造函数”呢?有边缘情况吗?我愿意承认我的无知。是的,instanceof
在构造函数中工作。使用new
调用函数时,基本上会发生以下情况:var newObj=Object.create(Constr.prototype);Constr.apply(newObj,参数);返回newObj代码>。超级调用应该没有问题,因为您应该在子构造函数中而不是在父构造函数中进行此测试。如果这个测试只在父母体内进行,它就不能正常工作。另一个缺点是如果你有一个可变构造函数。您不能将.apply
与新的
操作符一起使用(但请参见)。这将非常棒,但旧浏览器不支持“严格使用”@FelixKling建议在构造函数中使用instanceof
(而不是if(!this)
test)来获得相同的结果;用旧的browsers@dandavis:这将在旧浏览器中工作,但在严格模式下不起作用(其中此
将是未定义的
)。如果混合使用严格代码和非严格代码,或者希望代码与所有JavaScript引擎使用严格模式时的前向兼容,那么这是个坏主意。编辑:如果你的对象是故意设计用来扩展全局对象的,那也不好。@KarlGiesing:我不严格要求,但我的观点是明确的。这样做:如果(!this | | this.Math)返回新的人(姓名);在100%的情况下工作。除非您在原型上定义了“数学”,否则在这种情况下,请使用另一个江湖医生。@dandavis:这会考虑严格模式,但不会考虑将对象设计为扩展全局对象的边缘情况。在这种情况下,this.Array===Array
将始终返回true,并最终进入无限循环。但这是一个边缘案例,如果你有足够的知识来做这件事,你可能有足够的知识来知道为什么检查是坏的。