2

如何创建一个每次调用构造函数时都不会重新定义的 Javascript 私有方法?

据我所知,在 OOP-JS 中,私有方法是在一个“类”的“构造方法”中定义的方法,每次实例化一个新的“对象”时都会调用。我在想也许一个函数声明(即function name(),与函数表达式相反var name = function())可以解决问题,但我怎么能确定下面的代码只声明我的函数一次呢?

​function Tester() {
    function test () {
        console.log("executed");
    }
}
var t1 = new Tester();
var t2 = new Tester();
4

2 回答 2

4

如何创建一个每次调用构造函数时都不会重新定义的 Javascript 私有方法?

你不能(好吧,请参阅下面的一些回旋余地)。但是,除非您将拥有数千个 的实例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)

当然,或者,由于 usingcall比执行普通调用稍慢,您可以将实例作为参数传递:

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只有在出现问题时,额外的成本才是问题;除非你在一个紧密的循环中调用了数十万次,否则这不太重要。因此,是否使用callthis传递参数主要是一种风格选择。

于 2012-05-05T15:27:16.913 回答
2

我花了一段时间(来自 ActionScript 3 背景),但我觉得我应该与你分享我是如何学会停止担心并喜欢缺乏私有方法的;)

许多流行的 JavaScript 库,例如Backbone.jsjs-Signals只是使用一种命名约定,其中前导下划线表示私有成员,而不是使用稍微深奥的语法(尽管每个都有自己的!)。只是为了提供一些额外的上下文,Python 的文档甚至说 Python 根本不支持私有成员,并建议使用下划线来代替

JavaScript 是一种非常动态的语言;没有严格的类型检查和一些非常令人兴奋的范围界定;并且有一些非常酷的库可以利用这些事实,例如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');

抱歉,这个答案并没有真正回答你的问题(TJ 的答案在这方面几乎是教科书) - 我只是认为提供另一种可能的解决方案是值得的。

于 2012-05-05T18:10:27.547 回答