JavaScript Revealing Module pattern private variable state - javascript

I have recently started working on a JavaScript project and coming from Java world things seem, not surprisingly, weird at times.
I was implementing a simple module (Using revealing module pattern, afaik) which would provide config based on initialisation but notice that after a "local" variable domain is assigned in init() function its value differs depending whether it is accessed via a "getter" function getDomain() or directly via domain variable as exposed via modules "public" API.
See the following stripped down code which demonstrates the issue.
var ConfigManager = (function() {
var privateDomain = 'default';
function init(dom) {
privateDomain = dom;
}
function getDomain() {
return privateDomain;
}
return {
init: init,
domain: privateDomain,
getDomain: getDomain
};
})();
console.log(ConfigManager.domain); // Prints 'default'
console.log(ConfigManager.getDomain()); // Prints 'default'
ConfigManager.init('new domain');
console.log(ConfigManager.domain); // Prints 'default' <-- What??
console.log(ConfigManager.getDomain()); // Prints 'new domain'
At this point I am very confused how a variable returned from a getter function can have a different value when it is accessed directly?
Than you in advance!

Since privateDomain is a String, you're not copying / returning the reference, but the value.
Therefore when you're changing the domain using the init function, it just updates privateDomain, since domain has no link to it other than being a copy.
Hope it helps! :)

It's because when domain is returned, it's value is still "default". It's how Javascript works, more info here: Javascript by reference vs. by value
But when you use the function "getDomain" you will get the updated value.
Also have a look at the get/set syntax: Getter

Related

What is the proper use of super.call(this)

I have a class function (not originally developed by me)...
function Project()
{
Project.super.call(this);
// this._some_var = null;
/* other initial vars */
...
return DefensiveObject.create(this); // see comment below
}
function initialize()
{
//*******Initialize Project************
}
...
return Project;
This function is part of a module called "Project.js" included by running node main.js.
return DefensiveObject.create(this); // not return Object.create(this)
DefensiveObject is a class to prevent objects from getting or
setting properties that are not explicitly setup in the class.
The main.js calls Project.initialize() which resides within my Project class.
My question is why would there be a need to call "Project.super.call(this);"?
in Javascript the reserved word super is used on ES6 classes for referencing the parent of a child class, it doesn't makes sense to use it referencing a function.
please read this article where the usage of super is explained
https://jordankasper.com/understanding-super-in-javascript/
also this medium article can help you
https://medium.com/beginners-guide-to-mobile-web-development/super-and-extends-in-javascript-es6-understanding-the-tough-parts-6120372d3420
The Project.super.call(this) line was a way to allow use of a dispose method in a "Disposable" class (not included in the original question) which allowed for a clean up of code from memory.

Why is 'this' undefined in the debugger but printable in a console.log?

When setting a breakpoint on the console.log statement, why would this be undefined in the debugger but the statement print with no issues? Am I missing something in regards to scope here?
export class OptionsSidebarComponent {
...
public filters: Object = new Object();
...
public generateFilters() {
for (let property in this.terms) {
if (this.terms.hasOwnProperty(property) && this.terms[property] !== null) {
if (!this.filters.hasOwnProperty(this.productGroup.id)){
this.filters[this.productGroup.id] = new Filters();
}
this.terms[property].forEach((term) => {
console.log(this.filters);
});
}
}
}
}
With typescript While debugging, keep in mind that transpilers can rename variables. Using the original name in the console without sourcemaps that include renaming will show you undefined even if the original value isn't. Make sure you use the transpiled name in watches or console commands.
When you're referencing this with your console.log statement inside its own class, you're using it in its relevant scope. Depending on the framework you are using, different terms are used to reference your class... AngularJS used $scope- Angular 2+ uses this to reference the current class (or current scope/context).
When you use this in your debugger you're using it outside of its scope. It no longer references the class you intend it to.
Each one of your components in Angular uses this to reference itself. Here's an article to explain in further detail: https://angular-2-training-book.rangle.io/handout/features/refresher_on_this.html
If we simplify it to basic javascript and look at your class as just a function a good example would be this:
function example(){
var anything = 10;
console.log(anything); //output: 10
}
console.log(anything); //undefined! we're out of scope :)
So looking at it from this perspective, this is nothing magical. It's just provided to us by Angular to make our references to other things inside our components easier.

Using IIFEs in JS for protecting data by creating private variables

I have created a small program to print some message in the console when a button in the DOM is clicked.
Code-
<!DOCTYPE html>
<html>
<body>
<button onClick="printName()">Click</button>
</body>
<script>
const personDetails = (function() {
let name = 'john';
function displayMsg() {
console.log(name);
}
return {
displayName: displayMsg
}
})();
function printName() {
personDetails.displayName();
}
</script>
</html>
In above code, to protect name, I am using IIFE and returning a method displayName inside personDetails. On click of button, printName is executed which further executes personDetails.displayName. Here are my concerns -
Is this the right way to use IIFEs to protect the data? If no, then please provide a solution. This is getting confusing everyday.
Even if we are keeping only 1 global variables, other exposed
variables are accessible through the global one like displayName
method.
Let's say I have successfully protected the data, still I am able to
change the function definition in the console through
personDetails.displayName which should be avoided.
Old method:
function displayMsg() { console.log(name); }
New method:
personDetails.displayName = function() { console.log('Hiiii'); }
Welcome to StackOverflow. Please take the tour and visit the help center.
1. Is this the right way?
There is at least one 'close' vote for this question being primarily opinion-based. That voter is correct that this portion of the question is hard to answer definitively.
So let me just say that this is at least one appropriate way to do this. There are many others. You could simplify this, if you like, to
const personDetails = (function() {
let name = 'john';
return {
displayName: function() {
console.log(name);
}
}
})()
And you could simplify it still more by using arrow functions.
2. Why are other variables still exposed?
That is the point of such code: to create a public interface that makes reference to some private data. You could also skip personDetails and expose only displayName by returning the function and not an object with that function as a property.
But if you want to be able to use that data, then you need at least some public interface!
3. How is it that this function reference can still be changed?
There are techniques that would allow you to protect this variable from change. But then, perhaps, a user will redefine personDetails to be something else. Could you protect this? Maybe. But then what's to stop someone from intercepting your Javascript before it's interpreted by the browser, altering these definitions?
The point is that you will only ever have so much control. If you don't trust users, you shouldn't be shipping them code... which means you shouldn't be writing for the web.
Using IIFEs to protect data from accidental changes, or even well-meaning but dangerous intentional changes, is fine. Trying to pretend that you're entirely in charge of the code once it leaves your hands is folly however.
Yes
Yes, but there is only one global variable. This massively reduces the risk of other code accidentally overwriting it.
Yes. You can't stop deliberate modification to code once it has left your control and arrived at the client.
Minimising use of globals is a strategy to reduce the likelihood of bugs caused by other code. It isn't a form of DRM.
Let's say I have successfully protected the data, still I am able to
change the function definition in the console through
personDetails.displayName which should be avoided.
This can be avoided by changing the value of the writable property of the returned object.
Modify the function assignment of personDetails as follows:
"use strict";
const personDetails = (function() {
let name = 'john';
function displayMsg() {
console.log(name);
}
var obj = {};
Object.defineProperty(obj, 'displayName', {
value: displayMsg,
writable: false
});
return obj;
})();
Now, if anyone tries to overwrite the property value,
function printName() {
personDetails.displayName = 10;
}
printName();
you get an error like this:
Uncaught TypeError: Cannot assign to read only property 'displayName' of object '#<Object>'
at printName (<anonymous>:17:35)
Check out this writeup for more details.
Note: This will throw an error only in strict mode and silently reject any change otherwise.

Namespace import in node.js

I've got some function that allows to merge namespace, very similar to import when the module contains lot's of function (I expose an API with dozens of combinators)
It generates lots of var f = target.f; for every item from the export
function getNamespace(name, exports){
var output='';
for(var item in exports){
output += 'var ' + item + ' = '+name+ '.'+item + ';';
}
return output;
}
and usage:
var paco = require('./paco.js');
eval(paco.getNamespace('paco', paco));
// instead of paco.between(paco.start(),paco.content(),paco.end())
between(start(), content(), end())
Question:
I there a way to 'hide' the eval into the some function ? I don't want neither to mutate global namespace nor to call vm.runInThisContext, just need to add some local variables into the calling context after call function similar to require.
I mean I need something like
import('./paco');
// this should work like this
// var paco = require('./paco.js');
// var between = paco.between;
but without mutation of global and without eval in the calling scope.
tl;dr: No.
In order to understand why this is impossible, it's important to understand what Node is doing behind the scenes.
Let's say we define a function in test.js:
function foo() {
var msg = 'Hello world';
console.log(msg);
}
In traditional browser JavaScript, simply putting that function declaration in a file and pulling the file in with a <script> tag would cause foo to be declared in the global scope.
Node does things differently when you require() a file.
First, it determines exactly which file should be loaded based on a somewhat complex set of rules.
Assuming that the file is JS text (not a compiled C++ addon), Node's module loader calls fs.readFileSync to get the contents of the file.
The source text is wrapped in an anonymous function. test.js will end up actually looking like this:
(function (exports, require, module, __filename, __dirname) {
function foo() {
var msg = 'Hello world';
console.log(msg);
}
});
This should look familiar to anyone who has ever wrapped their own code in an anonymous function expression to keep variables from leaking into global scope in a browser. It should also start making sense how "magic" variables in Node work.
The module loader evals1 the source text from step 3 and then invokes the resulting anonymous function, passing in a fresh exports object. (See Module#_compile.)
1 - Really vm.runInThisContext, which is like eval except it does not have access to the caller's scope
After the anonymous wrapper function returns, the value of module.exports is cached internally and then returned by require. (Subsequent calls to require() return the cached value.)
As we can see, Node implements "modules" by simply wrapping a file's source code in an anonymous function. Thus, it is impossible to "import" functions into a module because JavaScript does not provide direct access to the execution context of a function – that is, the collection of a function's local variables.
In other words, there is no way for us to loop over the local variables of a function, nor is there a way for us to create local variables with arbitrary names like we can with properties of an object.
For example, with objects we can do things like:
var obj = { key: 'value' };
for (var k in obj) ...
obj[propertyNameDeterminedAtRuntime] = someValue;
But there is no object representing the local variables of a function, which would be necessary for us to copy the properties of an object (like the exports of a module) into the local scope of a function.
What you've done is generate code inside the current scope using eval. The generated code declares local variables using the var keyword, which is then injected into the scope where eval was called from.
There is no way to move the eval call out of your module because doing so would cause the injected code to be inserted into a different scope. Remember that JavaScript has static scope, so you're only able to access the scopes lexically containing your function.
The other workaround is to use with, but you should avoid with.
with (require('./paco.js')) {
between(start(), content(), end())
}
with should not be used for two reasons:
It absolutely kills performance because V8 cannot perform name lookup optimizations.
It is deprecated, and is forbidden in strict mode.
To be honest, I'd recommend that rather than doing something tricky with eval, do your future maintainers a favor and just follow the standard practice of assigning a module's exports to a local variable.
If you're typing it that often, make it a single-character name (or use a better editor).
According to this answer Global variables for node.js standard modules? there is global object the same as in browser there is window. So you can add key to that object
function getNamespace(exports) {
for(var item in exports){
global[item] = exports[item];
}
}
and use it as:
paco.getNamespace(paco);
no need for eval at all.
No. It's not possible to modify the local scope from an external module. Reason being, when eval is called in the external module, its context will be the external module, not the scope requiring the module.
In addition, vm.runInThisContext does not have access to the local scope, so that wont help you either.

Passing flags for functions via accessors - which JavaScript pattern is it?

I noticed the following pattern in socket.io-node:
// e.g. 1
socket.volatile.emit('bieber tweet', tweet);
// e.g. 2
socket.broadcast.json.send({ a: 'message' });
more generally, it seems to be of the style:
someObject.functionFlagA.functionFlagB.functionFlagEtc.someFunction(/* etc */);
What is this pattern called, where you add flags which may affect the execution of a function, in a chain of accessors which each return the target function (with any other available/appropriate chainable accessors)? When is it appropriate over, say, just passing some parameters to a function?
Looking at it gave me the idea of creating a sync object for my HTML5 web app like so:
// Saves someObj to localStorage AND to server-maintained session
sync.toLocalStorage.toServer.save(someObj);
...since it would be more self-documenting than:
// Saves someObj to localStorage AND to server-maintained session
sync.save(someObj, true, false, true);
Is this an appropriate use of above pattern?
EDIT 2011-12-06 13:06:15
For the curious, this is how socket.io implements it:
Socket.prototype.__defineGetter__('volatile', function () {
this.flags.volatile = true;
return this;
});
Which is used in chain to ultimately call the following internal function which sends a packet and clears the flags:
Socket.prototype.packet = function (packet) {
/* snip */
this.setFlags(); // clears this.flags
return this;
};
I would call it an example of a fluent interface.
From the Wikipedia article:
In software engineering, a fluent interface (as first coined by Eric
Evans and Martin Fowler) is an implementation of an object oriented
API that aims to provide for more readable code. A fluent interface is
normally implemented by using method chaining to relay the instruction
context of a subsequent call.
Of course in your example you have properties instead of methods. But looking at the socket.io-node code, the 'properties' are programmed as __defineGetter__ so you might as well say they are methods.
With regards to your sync object for HTML5: think about the state of the sync object after calling save. Is it reset to its original state or does it remember the configuration? What happens if you call save twice in a row?
If it's just about readability, you can also have callers pass in the configuration like so:
sync.save(someObj, { toLocalStorage: true, toServer: true });

Categories

Resources