根据我对javascript的理解,原型方法无法访问构造函数范围内的私有变量,
var Foo = function() {
var myprivate = 'I am private';
this.mypublic = 'I am public';
}
Foo.prototype = {
alertPublic: function() { alert(this.mypublic); } // will work
alertPrivate: function() { alert(myprivate); } // won't work
}
这很有道理,但有什么方法可以安全和良好的做法吗?由于使用原型提供了性能优势,因为成员函数只分配了一次,我想实现类似的功能,同时仍然可以访问我的私有变量。我不认为它会使用原型,但是有另一种模式,例如工厂方法或闭包方法吗?像,
var fooFactory = function() {
var _alertPrivate = function(p) { alert(p); } // bulk of the logic goes here
return function(args) {
var foo = {};
var myprivate = args.someVar;
foo.mypublic = args.someOtherVar;
foo.alertPrivate = function() { _alertPrivate(myprivate); };
return foo;
};
}
var makeFoo = new fooFactory();
var foo = makeFoo(args);
我不确定每次创建新Foo时是否创建了_alertPrivate的新副本,或者是否有任何潜在的性能优势。目的是获得类似于原型的功能(因为它节省了内存),同时仍然能够访问私有变量。
感谢。
答案 0 :(得分:4)
到目前为止,我已经提出了以下模式来解决这个问题。我需要的是一个特权设置器,以便私有变量可以从某些原型函数内部更改,但不能从其他任何地方更改:
var Foo = (function() {
// the bulk of the objects behavior goes here and is created once
var functions = {
update: function(a) {
a['privateVar'] = "Private variable set from the prototype";
}
};
// the objects prototype, also created once
var proto = {
Update: function() {
this.caller('update');
}
};
// special function to get private vars into scope
var hoist = function(accessor) {
return function(key) {
return functions[key](accessor());
}
}
// the constructor itself
var foo = function foo() {
var state = {
privateVar: "Private variable set in constructor",
// put more private vars here
}
this.caller = hoist(function(){
return state;
});
}
// assign the prototype
foo.prototype = proto;
// return the constructor
return foo;
})();
基本上,一个指向对象内部状态的指针通过一个简单的访问器函数()的返回状态被提升到它的原型{return state; }。在任何给定实例上使用“调用者”函数允许您调用仅创建一次但仍可引用该实例中保存的私有状态的函数。同样重要的是要注意原型之外的任何函数都不能访问特权访问器,因为“调用者”只接受一个引用范围内预定义函数的键。
以下是此方法的一些基准测试,以了解它与纯原型的比较。这些图表示在循环中创建对象的80,000个实例(请注意,用于基准测试的对象比上面的对象更复杂,仅用于简化目的):
反转片:
仅关闭 - 2172毫秒
原型设计(以上方式) - 822ms
原型设计(标准方式) - 751ms
FIREFOX:
仅关闭 - 1528ms
原型设计(以上方式) - 971ms
原型设计(标准方式) - 752ms
正如您所看到的,该方法几乎与正常原型一样快,并且绝对比仅使用将函数与实例一起复制的常规闭包更快。
答案 1 :(得分:1)
我发现Sean Thoman的回答很有帮助(虽然起初很难理解)。
看起来公共制定者不能接受privateVar
的值,所以我做了一些调整:
更改update
中的functions
:
update: function(st, newVal) {
st['privateVar'] = newVal;
}
更改Update
中的proto
:
Update: function(newVal) {
this.caller('update', newVal);
}
更改hoist
:
var hoist = function(accessor) {
return function(key) {
// we can't slice arguments directly because it's not a real array
var args_tail = Array.prototype.slice.call(arguments, 1);
return functions[key].apply(functions[key], [accessor()].concat(args_tail));
}
}
答案 2 :(得分:1)
你要求的是可能的,尽管在性能(速度或内存)和功能之间总会存在权衡。
在JavaScript中,可以实现私有的每个实例状态,使用普通的原型方法(并且没有集中的,泄漏的,字段存储)。
查看我撰写的关于该技术的文章:http://www.codeproject.com/KB/ajax/SafeFactoryPattern.aspx
或者直接转到https://github.com/dcleao/private-state中的源代码。