JS Private methods not redefined at each constructor call

廉价感情. 提交于 2019-12-12 17:31:58

问题


How do you make a Javascript private method that is not redefined each time you call the constructor ?

As far as I know, in OOP-JS, private methods are methods defined in the "constructor method" of one's "class", called each time one instantiates a new "object". I was thinking maybe a function declaration (i.e. function name(), as opposed to function expression var name = function()) would do the trick, but how can I be sure that the following code only declares my function once ?

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

回答1:


How do you make a Javascript private method that is not redefined each time you call the constructor ?

You can't (well, see below for a bit of wiggle room). But unless you're going to have thousands of instances of Tester, don't worry about it too much; most engines probably reuse the underlying code across the multiple function objects that get created. (The code, mind; not the function object or the context it closes over, which must be unique and allocated each time. But they need not be large. Of course, quite a function functions are fairly small as well...)

...how can I be sure that the following code only declares my function once ?

You can be sure that it doesn't; it declares the function each time Tester is called. Witness:

​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"

Note that you can have functions that are private to the implementation, but not assigned to any instance of the object. The module pattern is handy for doing that:

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

There, privateFunction is completely private, accessible only to the code within the anonymous function. And there's only one copy of it, but you can call it as though you were calling a method of a Tester instance using privateFunction.call(this).

Alternately, of course, since using call is slightly slower than doing a normal call, you could just pass the instance as an argument:

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

Of course, the extra cost of call is only a problem if and when it's a problem; unless you're calling something hundreds of thousands of times in a tight loop, it's unlikely to matter. So whether to use call and this or pass an argument would be primarily a style choice.




回答2:


It took me a while (coming form an ActionScript 3 background), but I feel that I should share with you how I learned to stop worrying and love the lack of private methods ;)

Many popular JavaScript libraries, such as Backbone.js and js-Signals simply make use of a naming convention where a leading underscore denotes private members as opposed to using slightly esoteric syntax (although each to their own!). Just to give this some additional context, Python's documentation goes as far as saying that Python does not support private members at all and suggests using an underscore instead.

JavaScript is a very dynamic language; there's no strict type checking and some really exciting scoping; and there are some really cool libraries out there which take advantage of those facts, such as SinonJS which makes it effortless to achieve meaningful test coverage in your codebase; for example:

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');

Sorry this answer doesn't really answer your question (T.J's answer is pretty much textbook in that regard) - I just thought it would be worthwhile to offer another possible solution.



来源:https://stackoverflow.com/questions/10463245/js-private-methods-not-redefined-at-each-constructor-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!