JS私有方法不会在每个构造函数调用时重新定义

JS Private methods not redefined at each constructor call

本文关键字:函数调用 新定义 定义 有方法 JS      更新时间:2023-09-26

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

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

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

如何使每次调用构造函数时都不会重新定义的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是完全私有的,只有匿名函数中的代码才能访问。它只有一个副本,但您可以像使用 privateFunction.call(this) 调用Tester实例的方法一样调用它。

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

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

许多流行的JavaScript库,如Backbone.js和js-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');

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