How to call a public function from a private function in a JavaScript module template

How to call a public function from a private function in a JavaScript module template?

For example, in the following code

var myModule = (function() { var private1 = function(){ // How to call public1() here? // this.public1() won't work } return { public1: function(){ /* do something */} } })(); 

This question has been asked twice before , with a different accepted answer for everyone.

  • Save the link to the returned object before returning it, and then use this link to access the public method. See the answer .
  • Keep the public method link in the closure and use this to access the public method. See the answer .

Although these solutions work, they are unsatisfactory from the point of view of OOP. To illustrate what I mean, give a concrete implementation of a snowman with each of these solutions and compare them with a simple object literal.

Snowman 1: Save Link to Return Object

 var snowman1 = (function(){ var _sayHello = function(){ console.log("Hello, my name is " + public.name()); }; var public = { name: function(){ return "Olaf"}, greet: function(){ _sayHello(); } }; return public; })() 

Snowman 2: Save link to public function

 var snowman2 = (function(){ var _sayHello = function(){ console.log("Hello, my name is " + name()); }; var name = function(){ return "Olaf"}; var public = { name: name, greet: function(){ _sayHello(); } }; return public; })() 

Snowman 3: literal object

 var snowman3 = { name: function(){ return "Olaf"}, greet: function(){ console.log("Hello, my name is " + this.name()); } } 

We see that the three are identical in functionality and have the same public methods.

If we do a simple redefinition test, however

 var snowman = // snowman1, snowman2, or snowman3 snowman.name = function(){ return "Frosty";} snowman.greet(); // Expecting "Hello, my name is Frosty" // but snowman2 says "Hello, my name is Olaf" 

we see that # 2 fails.

If we run a prototype override check,

 var snowman = {}; snowman.__proto__ = // snowman1, snowman2, or snowman3 snowman.name = function(){ return "Frosty";} snowman.greet(); // Expecting "Hello, my name is Frosty" // but #1 and #2 both reply "Hello, my name is Olaf" 

we see that both # 1 and # 2 fail.

This is a really ugly situation. Just because I decided to somehow reorganize my code, the user of the returned object should carefully examine how I implemented everything to find out if it can override my object methods and expect it to work! While opinions differ here, my own opinion is that the correct override behavior is a simple object literal.

So this is the real question:

Is there a way to call an open method from private so that the resulting object acts as an object literal with respect to overriding behavior?

+8
javascript module-pattern
source share
2 answers

You can use this to get the object that your preferred greet method has been called on.

You can then pass this value to your private _sayHello method, for example. using call , apply or as an argument:

 var snowman4 = (function() { var _sayHello = function() { console.log("Hello, my name is " + this.name); }; return { name: "Olaf", greet: function() { _sayHello.call(this); } }; })(); 

Now you can do

 var snowman = Object.create(snowman4); snowman.greet(); // "Hello, my name is Olaf" snowman.name = "Frosty"; snowman.greet(); // "Hello, my name is Frosty" 

And

 snowman4.greet(); // "Hello, my name is Olaf" snowman4.name = "Frosty"; snowman4.greet(); // "Hello, my name is Frosty" 
+2
source share

With a module template, you hide all innate objects in local variables / functions and usually use them in your public functions. Each time a new object is created with a module template, a new set of public functions is created - with its own cloud area.

With the prototype template, you have the same set of methods available for all objects of a particular type. What changes for these methods is this object - in other words, their state. But this never hidden.

Needless to say, it's hard to mix. One possible way is to extract the methods used by individuals in the prototype of the resulting module object using Object.create . For example:

 var guardian = function() { var proto = { greet: function () { console.log('I am ' + this.name()); }, name: function() { return 'Groot'; } }; var public = Object.create(proto); public.argue = function() { privateGreeting(); }; var privateGreeting = public.greet.bind(public); return public; }; var guardian1 = guardian(); guardian1.argue(); // I am Groot var guardian2 = guardian(); guardian2.name = function() { return 'Rocket'; }; guardian2.argue(); // I am Rocket var guardian3 = guardian(); guardian3.__proto__.name = function() { return 'Star-Lord'; }; guardian3.argue(); // I am Star-Lord 
+1
source share

All Articles