简体   繁体   中英

JavaScript: calling private method's property on class object

For the class Engine , " start " and " stop " are two public methods which internally calls " ignitionOn " and " ignitionOff ". After " start " is called the private method sets a variable " ignitionIndicator " to " true " on the engine instance and " stop " sets it to " false ".

However that is not happening. Something is going wrong since the "ignitionIndicator" value is always "undefined". I have to keeping the following in mind.

(i) Visibility of the methods should be as it is.

(ii) I CAN NOT set the variable directly from the public methods . The variable should be only and only set from within the private method .

function Engine() {
  function EngineConstructor() { };

  // publicly accessible methods
  EngineConstructor.prototype.start = function() {
    ignitionOn();
  };

  EngineConstructor.prototype.stop = function() {
    ignitionOff();
  };

  // private methods 
  function ignitionOn() {
    // does other things and sets this to true
    this.ignitionIndicator = true;
  };

  function ignitionOff() {
    // does other things and sets this to false
    this.ignitionIndicator = false;
  };

  return new EngineConstructor();  
};
var e = new Engine();
e.start();
e.ignitionIndicator // undefined, should have been true
e.stop();
e.ignitionIndicator // undefined, should have been false

You'd need to call those methods such that this refers to an instance, for instance via Function#call or Function#apply , eg:

EngineConstructor.prototype.start = function() {
    ignitionOn.call(this);
};

Or alternately, just pass the instance as an argument (procedural style):

EngineConstructor.prototype.start = function() {
    ignitionOn(this);
};

// ...

function ignitionOn(instance) {
    // does other things and sets this to true
    instance.ignitionIndicator = true;
}

The pattern you're using in that code is very odd. You have a function, Engine , which you use as a constructor (via new ) but which isn't a constructor (it returns something other than the instance created by the new operator), and the object it returns is unrelated to the Engine function — instead, it's an instance created by EngineConstructor . Worse, it creates a whole new EngineConstructor every time you call it. This is hugely inefficient; if you want to recreate all the methods for every instance, you can do so much more simply.

But I'd just revisit the entire structure so that you do get method reuse. If the goal is to have a constructor function which has access to private methods from prototype methods, the revealing module pattern (applied here to a single constructor) is the usual way to do that:

 var Engine = function() { // The constructor function Engine() { } // Publicly accessible methods Engine.prototype.start = function() { ignitionOn.call(this); }; Engine.prototype.stop = function() { ignitionOff.call(this); }; // Private methods function ignitionOn() { // does other things and sets this to true this.ignitionIndicator = true; } function ignitionOff() { // does other things and sets this to false this.ignitionIndicator = false; } return Engine; }(); var e = new Engine(); e.start(); snippet.log(e.ignitionIndicator); e.stop(); snippet.log(e.ignitionIndicator); 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 


Side note: Function declarations don't have a ; after them. ; is a statement terminator, and function declarations (such as those for ignitionOn and ignitionOff ) are not statements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM