如何在每次调用构造函数时都创建一个未重新定义的Javascript私有方法?
据我所知,在OOP-JS中,私有方法是在一个“类”的“构造函数方法”中定义的方法,每次实例化一个新的“对象”时调用。我想也许是一个函数声明(即function name()
,而不是函数表达式var name = function()
)会做的伎俩,但我怎么能确定下面的代码只声明我的函数一次?
function Tester() {
function test () {
console.log("executed");
}
}
var t1 = new Tester();
var t2 = new Tester();
答案 0 :(得分:4)
如何在每次调用构造函数时都创建一个未重新定义的Javascript私有方法?
你不能(好吧,请看下面的一些摆动空间)。但除非你有成千上万的{{1}}个实例,否则不要太担心;大多数引擎可能会在创建的多个函数对象中重用底层代码。 (代码,介意;不是函数对象或它关闭的上下文,必须每次都是唯一的和分配的。但它们不需要很大。当然,功能函数相当小......)
...我怎么能确定以下代码只声明我的函数一次?
你可以肯定它没有;它每次调用Tester
时声明该函数。证人:
Tester
请注意,您可以拥有实现专用的功能,但不能分配给该对象的任何实例。模块模式非常方便:
function Tester() {
this.test = test;
function test () {
console.log("executed");
}
}
var t1 = new Tester();
var t2 = new Tester();
console.log(t1.test === t2.test); // "false"
在那里,var Tester = (function() {
function Tester(name) {
this.name = name;
}
Tester.prototype.publicFunction = function() {
privateFunction.call(this);
};
function privateFunction() {
console.log("My name is " + this.name);
}
return Tester;
})();
var t = new Tester("Fred");
t.publicFunction(); // Outputs "My name is Fred" via the private function
是完全私有的,只能访问匿名函数中的代码。并且它只有一个副本,但您可以将其称为使用privateFunction
调用Tester
实例的方法。
或者,当然,因为使用privateFunction.call(this)
稍微比执行普通调用慢,所以您可以将实例作为参数传递:
call
当然,var Tester = (function() {
function Tester(name) {
this.name = name;
}
Tester.prototype.publicFunction = function() {
privateFunction(this);
};
function privateFunction(t) {
console.log("My name is " + t.name);
}
return Tester;
})();
var t = new Tester("Fred");
t.publicFunction(); // Outputs "My name is Fred" via the private function
的额外费用只是一个问题,如果它是一个问题;除非你在一个紧凑的循环中召唤成千上万次,否则不太重要。因此,是否使用call
和call
或传递参数主要是一种风格选择。
答案 1 :(得分:2)
我花了一段时间(来自ActionScript 3背景),但我觉得我应该与你分享how I learned to stop worrying and love the lack of private methods;)
许多流行的JavaScript库,例如Backbone.js和js-Signals只是使用命名约定,其中前导下划线表示私有成员,而不是使用稍微深奥的语法(尽管每个都是自己的!) 。为了给出一些额外的上下文,Python的文档就是说Python根本不支持私有成员suggests using an underscore instead。
JavaScript是一种非常动态语言;没有严格的类型检查和一些really exciting scoping;并且有一些非常酷的库可以利用这些事实,例如SinonJS,这使得在代码库中实现有意义的测试覆盖变得毫不费力;例如:
var instance = new Car("ford");
// Replace the car's engine with test stub.
// Alternative syntax: sinon.stub(instance, '_engine');
instance._engine = sinon.stub(instance._engine);
car.start();
// As the '_engine' object has been mocked it gains new attributes.
ok(instance._engine.checkOil.calledOnce, 'Oil level was checked');
很抱歉,这个答案并没有真正回答你的问题(T.J的答案就是这方面的教科书) - 我只是觉得提供另一种可能的解决方案是值得的。