JavaScript Jems - The Revealing Constructor Pattern |
Written by Mike James | ||||
Thursday, 27 March 2025 | ||||
Page 2 of 3
Private MethodsModern Promises use a modification on the standard way that constructors provide private methods called the revealing constructor pattern. You don’t need to understand how this works to consume or even produce Promises, but it isn’t difficult and it might well have other uses so it is worth knowing about. Like all JavaScript patterns, once you have seen it, it seems more than obvious. First let’s see how to create a private method – if you are sure you know how, skip to the next section. A private method is one that is created as a closure when an object is created. This is the standard method for creating a private variable accessible from within an object, but not from outside. The only difference is that the variable references a function. For example, to create a private variable: function myConstructor(){ var private=0; this.myFunction=function(){ alert(private); } } This is a constructor for an object with just one method, myFunction. The important part is the variable private. This is not part of the object because it isn't declared as a property of the object. so if you try: var myObject=new myConstructor(); myObject.private=1; you will see an error that private doesn't exist. However, as private is in scope when myFunction is declared, it is available to it as a closure. That is: myObject.myFunction(); does display the value of private. A private method uses the same mechanism with the small difference that the variable references a function – an inner function which is not a method of the object being constructed. This is the mechanism that the JavaScript Promise uses to make resolve and reject private methods, but with some additional twists. The main twist is that private functions and variables are accessed by a function that is passed to the constructor i.e. the executor. Let’s see how this works. Suppose you need to set a private variable to some value when the constructor is used but after that it is private and inaccessible. The simplest solution is: function myClass(value){ var myPrivateVar=value; this.myMethod=function(){ console.log(myPrivateVar); } } Now you can create an instance using: var myObject=new myClass(10); myObject.myMethod(); The value of the private variable will be printed, i.e. 10, and this has been set when the constructor was used, but the variable cannot now be altered by code external to the object. This seems simple enough, but if we push the idea just a little further it gets a little bit more difficult. What happens if you want to pass a function in the constructor call that works with private members of the object being constructed? The function is intended to be executed by the constructor as the object is being created. A first attempt might be something like: function myClass(func) { var myPrivateVar = Math.random(); var reveal = function (){ return myPrivateVar; } func(); This creates a private variable set to a random value which can be discovered by accessing the private method reveal and func is a function, passed into the constructor and then executed, which can make use of reveal to access the value. The idea is that we are trying to allow the passed in function access to private variables that the object being constructed has access to only because of closure. If you try it out by passing it a function that tries to make use of reveal: var myObject = new myClass( function () { console.log(reveal()); } ); you will see an error message generated when func is called saying the reveal is undefined. The error here is obvious, reveal is not in scope for the function passed into the constructor. Which variables a function can access is determined by where the function is declared, not where it is used. That is, the variables myPrivateVar and reveal are not global to the function passed in. They exist, but they are out of scope. It might be easier to see this if we re-write the use of the constructor to show more clearly where the function is defined: let myFunc=function () { console.log(reveal()); } var myObject = new myClass(myFunc); |
||||
Last Updated ( Saturday, 29 March 2025 ) |