I've implemented a library that exposes a function speach() to create an object with specific public API functions. The functions proxy to an internal object class Speach which I don't expose to the end-user so the implementation details cannot be touched. I can change implementation details later as long as I continue to support the publicly exposed API.
Is there a name for this pattern?
class Speach {
constructor() {
// ...
}
browserSupportsFeature() {}
loadAPI() {}
voice(name) {
// ...
}
speak(textToSpeak) {
// ...
}
then(onFulfilled, onRejected) {
// ...
}
}
const speach = () => {
const speach = new Speach();
return {
voice(name) {
speach.voice(name);
return this;
},
speak(textToSpeak) {
speach.speak(textToSpeak);
return this;
},
then(thenable) {
speach.then(thenable);
return this;
}
};
};
Abstraction.
Abstraction is when you hide implementation details and only expose the interface to the client. The developer can change the underlying implementation as they please as long as the outside interface stays the same.
Restricting access to variables by limiting their scope inside a closure is called information hiding.
This implementation is basically the the Module pattern.
Related
I have 2 classes, one of them is a general utility class used by the entire application. I would like to reference the this property of the caller class in the callee utility class.
I am unsure what the best practice for this is.
I have provided an example of what I'm trying to do.
I one case I can use .call to provide the correct this context or I can pass this in as a function parameter.
class Caller {
doSomething() {
Utility.calledMethod.call(this, 'paramStr');
Utility.calledMethodWithThis(this, 'paramStr');
}
doAnotherThing(param) {
console.log(param);
}
}
// Shared Class of utility methods used for entire application
class Utility {
static calledMethod(param) {
this.doAnotherThing(param);
}
static calledMethodWithThis(self, param) {
self.doAnotherThing(param);
}
}
const caller = new Caller();
caller.doSomething();
https://jsfiddle.net/pvafedho/
This looks like a scenario where you can utilize a mixin.
Following the example from this page: https://javascript.info/mixins
Your code could look like this:
// Shared Class of utility methods used for entire application
let utilityMixin = {
calledMethod(param) {
this.doAnotherThing(param);
}
}
class Caller {
constructor() {
this.mystring = 'hello!'
}
doSomething() {
this.calledMethod(this.mystring);
}
doAnotherThing(param) {
console.log(param);
}
}
Object.assign(Caller.prototype, utilityMixin );
const caller = new Caller();
caller.doSomething();
I'm struggling with my JS code structure that's becoming apparent during my unit testing attempts. I'm used to the class structure, but I'm a bit lost in the JS world where there aren't any classes. I'm looking for a way to organize my code in the traditional class/constructor architecture. Here's what I have:
function ddGridSelector(primaryId, templateDefault, gridObj) {
//set the variables
this.primaryId = primaryId,
this.defaultTemplate = templateDefault,
this.gridObj = gridObj,
this.gridObj.searchVal = '',
this.init = ddgs_init
}
function ddgs_init(ddgs_obj) {
ddgs_setDefaultTemplate(ddgs_obj);
ddgs_initGrid(ddgs_obj);
ddgs_initKendoWindow(ddgs_obj);
ddgs_initKendoButton(ddgs_obj);
ddgs_initResetButton(ddgs_obj);
ddgs_addGridEventListener(ddgs_obj);
}
function ddgs_setDefaultTemplate(ddgs_obj) {
//doing stuff
}
function ddgs_initGrid(ddgs_obj) {
//more stuff
}
To call any of these...
var ddGridSelector_new = new ddGridSelector('PrimaryIdentifier', templateDefault, gridObj);
ddGridSelector_new.init(ddGridSelector_new);
It seems really redundant to pass my object to my function that's specified in my constructor so I'm sure I'm missing something obvious here. Really would appreciate some guidance on the matter. I think I'm close to being on a good path.
ES5 Way
You can do "functional classes" like this, which are pretty self explainable:
function User(name) {
// name is thus "private" here because it's
// not put under "this.name"
this.sayHi = function() {
alert(name);
};
}
let user = new User("John");
user.sayHi(); // John
There's also the prototype class pattern as well:
function User(name, birthday) {
this._name = name;
}
User.prototype.sayHi = function() {
alert(this._name);
};
let user = new User("John");
user.sayHi(); // John
Source/Tutorial with the examples listed here
ES6+ Way
In ES6 you can declare classes in a way that looks more like traditional programming languages:
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
let user = new User("John");
user.sayHi(); // John
However you will need a transplier like Babel or Typescript to compile it down to web compatible code if you are targeting platforms such as IE (all versions), Opera Mini, and the Android Browser (4.4.x, ~16% of all Android versions in the field) (web compat sources), or things such as Cordova on older iOS devices (< 10, UIWebView, etc).
Node.js should have support for classes from 4.8.4(!) and above, surprisingly enough (source).
but I'm a bit lost in the JS world where there aren't any classes.
But... there are!
class ddGridSelector {
constructor(primaryId, templateDefault, gridObj) {
//set the variables
this.primaryId = primaryId,
this.defaultTemplate = templateDefault,
this.gridObj = gridObj,
this.gridObj.searchVal = '',
}
init() {
this.setDefaultTemplate();
this.initGrid();
this.initKendoWindow();
this.initKendoButton();
this.initResetButton();
this.addGridEventListener();
}
setDefaultTemplate() {
//doing stuff
}
initGrid() {
//more stuff
}
}
I tend to love this structure for a class-like layout when I want to avoid new features. It gives you a private scope where you can scope functions and shared variables as you need them and lets you separate out a "constructor" and public methods on the prototype.
var MyType = (function () {
function MyType() {
//My Constructor
}
MyType.prototype = {
constructor: MyType,
publicMethod: privateMethod
};
function privateMethod() {
...
}
return MyType;
}());
The outer scope runs immediately and keeps the global namespace clean. We augment the private function with prototype instance methods, define any "private" methods needed, and return the private type after setup. This lets you instantiate a class like normal and call any methods.
var example = new MyType();
example.publicMethod();
I am trying to find a way to create an simili-abstract class in ES6. So far, everything I try always hits the limitations of the langage and/or its syntax (also my limited knowledge about prototyping).
Basic oop; We declare a class and extend it. The final class has to access some fields and methods from its superclass, but not all of them. It also morphs public methods...
The class declarations should be in a perfect encapsulation, so nothing else than this code is be able to reach it (something similar to a namespace).
So far, my experiments in ES5 are wrong... I would really appreciate some advice and help.
(function(){
// ==================================
function AbstractClass(params) {
var _myParams = params;
var _privateField = "Only AbstractClass can see me";
this.publicField = "Everybody can see me";
function privateFunc() {
// Does private stuff
}
}
AbstractClass.prototype.publicFunc = function() {
// Does public stuff
privateFunc(); // Works?
}
// ==================================
function FinalClass(params) {
// How to pass the params to the superclass?
}
FinalClass.prototype.publicFunc = function() {
// Override and calls the superclass.publicFunc()?
// How can I touch _privateField ? publicField ?
}
FinalClass.prototype = Object.create(AbstractClass.prototype);
// ==================================
var foo = new FinalClass("hello world!");
foo.publicFunc();
})();
Can you tell me what is wrong with this code and how to fix it?
Bonus question: How to do this in ES6 properly?
Triple bonus: What about protected fields and methods?
Thank you.
This is actually a very good question and I will try to give you an insightful answer...
As I already explained somewhere on Stack Overflow, JavaScript is not really a class-based language. It is based on prototypes. This is a completely different programming paradigm and you should take this into consideration. So when you write something in Vanilla JS, this is generally a good idea to forget (just a tad) what you know about Java or C++.
However, JavaScript is a very flexible language and you can program as you wish. In my opinion, there are two main styles when it comes to JavaScript programming: an idiomatic style and a classic style.
The idomatic style makes intensive use of object literals, duck typing, factory functions and composition.
The classic style tries to mimic the behavior of class-based languages with constructor functions for classes and IIFEs (Immediately-Invoked Function Expressions) for encapsulation. It lays stress on inheritance and polymorphism.
What you want is an abstract class. An abstract class is a class that cannot be instantiated and is only useful as a model for derived classes. If you care about strict encapsulation, this is how you could implement it in ES5:
// ==============================
// ABSTRACT "CLASS"
// ==============================
var OS = (function (n) {
// Here "name" is private because it is encapsulated in the IIFE
var name = "";
// Constructor
function OS (n) {
// If "OS" is called with "new", throw an error
if (this.constructor === OS) {
throw new Error('You cannot instantiate an abstract class!');
}
name = n;
}
// We cannot call this method directly (except with "call" or "apply") because we cannot have direct instances of "OS"
OS.prototype.boot = function () {
return name + ' is booting...';
};
// This is an abstract method. It will be in the prototype of derived objects but should be overriden to work
OS.prototype.shutdown = function () {
throw new Error('You cannot call an abstract method!');
};
// Getter for "name"
OS.prototype.getName = function () {
return name;
};
// The constructor must be returned to be public
return OS;
})();
// ==============================
// CONCRETE "CLASS"
// ==============================
var LinuxDistro = (function (name) {
// Constructor
function LinuxDistro(name) {
// Here we call the constructor of "OS" without "new", so there will not be any error
OS.call(this, name);
}
// Here "Linux Distro" inherits from "OS"
LinuxDistro.prototype = Object.create(OS.prototype);
LinuxDistro.prototype.constructor = LinuxDistro;
// Private function/method
function textTransform(str, style) {
return style === 'lowercase' ? str.toLowerCase() : str.toUpperCase();
}
// The parent method is used and overriden
LinuxDistro.prototype.boot = function () {
return OS.prototype.boot.call(this) + ' Welcome to ' + textTransform(this.getName());
};
// The abstract method is implemented
LinuxDistro.prototype.shutdown = function () {
return 'Shutting down... See you soon on ' + textTransform(this.getName());
};
// The constructor must be returned to be public
return LinuxDistro;
})();
// ==============================
// CLIENT CODE
// ==============================
var arch = new LinuxDistro('Arch Linux');
console.log(arch.getName());
console.log(arch.boot());
console.log(arch.shutdown());
Now you want the same thing with ES6. The good point is that ES6 provides nice syntactic sugar to work with classes. Again, if you care about strict encapsulation, you could have the following implementation:
// ==============================
// ABSTRACT "CLASS"
// ==============================
const OS = (n => {
// Here "name" is private because it is encapsulated in the IIFE
let name = "";
class OS {
constructor(n) {
// If "OS" is called with "new", throw an error
if (new.target === OS) {
throw new Error('You cannot instantiate an abstract class!');
}
name = n;
}
// We cannot call this method directly (except with "call" or "apply") because we cannot have direct instances of "OS"
boot() {
return `${name} is booting...`;
}
// This is an abstract method. It will be in the prototype of derived objects but should be overriden to work
shutdown() {
throw new Error('You cannot call an abstract method!');
}
// Getter for "name"
get name() {
return name;
}
}
// The class must be returned to be public
return OS;
})();
// ==============================
// CONCRETE "CLASS"
// ==============================
const LinuxDistro = (name => {
// Private function/method
function textTransform(str, style) {
return style === 'lowercase' ? str.toLowerCase() : str.toUpperCase();
}
class LinuxDistro extends OS {
constructor(name) {
// Here we call the constructor of "OS" without "new", so there will not be any error
super(name);
}
// The parent method is used and overriden
boot() {
return `${super.boot()} Welcome to ${textTransform(this.name)}`;
}
// The abstract method is implemented
shutdown() {
return `Shutting down... See you soon on ${textTransform(this.name)}`;
}
}
// The class must be returned to be public
return LinuxDistro;
})();
// ==============================
// CLIENT CODE
// ==============================
const arch = new LinuxDistro('Arch Linux');
console.log(arch.name); // This is not a direct access to "name". The getter is used...
console.log(arch.boot());
console.log(arch.shutdown());
Of course, these snippets are not perfect and may look a bit scary. But I think this is the best we can do, due to the prototypal nature of JavaScript.
As you probably see, class members are either private (thanks to IIFEs and closures) or public (thanks to how objects are created, with their own properties and prototype chain). If you really want protected members, this is another story...
When you have in mind an OOP model for your JavaScript code, I would recommend you to use TypeScript. This is much more convenient, readable and maintainable than the code presented above.
Finally, if you want to go further and see how you could implement all traditional OOP design patterns in JavaScript (especially GoF patterns), I invite you to take a look at a project of mine on GitHub: PatternifyJS
What is the perpose of calling privateMethod from the publicMethod?
Can't we just define the content of privateMethod inside the public method and do the same thing ?
var basketModule = (function() {
var basket = [];
function privateMethod() {
console.log(basket);
}
return {
publicMethod: function(){
privateMethod();
}
};
})());
basketModule.publicMethod();
In your simple example, there is not really a reason for privateMethod to exist because all publicMethod does is call it, but in a more real-world example, the private methods would do things that you don't want other modules calling on their own.
For example, this is a snippet of code that I worked on today, reduced to make it a good example:
(function(){
function _renderTreeLevel() { ... }
function _backfillAllSelectedStates() { ... }
function _updateSelectedCount() { ... }
return {
render: function() {
var expandCollapse = new ExpandCollapse();
expandCollapse.render();
_renderTreeLevel(0, this.ui.treeRegion, this.treeData);
_backfillAllSelectedStates();
_updateSelectedCount((this.options.selected || []).length);
$('.collapse').collapse();
}
};
})();
The 3 "private" function that start with '_' are just functions that I put code into for refactoring and making the code cleaner and more reusable. They are not functions that I want someone to be able to call.
Users of this module should call render() only.
The reasoning is the same as any other language that has public and private members built-in, like C# or Java, but since JavaScript doesn't provide that concept, this is the pattern that people follow to provide a similar behavior.
I'm trying to create my custom toolbox which imitates jQuery's design pattern. Basically, the idea is somewhat derived from this post: jQuery plugin design pattern (common practice?) for dealing with private functions (Check the answer given by "David").
So here is my toolbox function:
(function(window){
var mySpace=function(){
return new PrivateSpace();
}
var PrivateSpace=function(){
var testCache={};
};
PrivateSpace.prototype={
init:function(){
console.log('init this:', this);
return this;
},
ajax:function(){
console.log('make ajax calls here');
return this;
},
cache:function(key,selector){
console.log('cache selectors here');
testCache[key]=selector;
console.log('cached selector: ',testCache);
return this;
}
}
window.hmis=window.m$=mySpace();
})(window)
Now, if I execute this function like:
console.log(m$.cache('firstname','#FirstNameTextbox'));
I get an error 'testCache' is not defined. I'm not able to access the variable "testCache" inside my cache function of the prototype. How should I access it? Basically, what I want to do is, I want to cache all my jQuery selectors into an object and use this object in the future.
testCache is hidden in the closure that new PrivateSpace creates.
The correct pattern to use here is
var PrivateSpace=function(){
this.testCache={};
};
PrivateSpace.prototype={
cache:function(key,selector){
this.testCache[key]=selector;
return this;
}
}
The essential part here is this.
But the entire piece of code seems a bit contrived - there is no reason to use a prototype pattern when only a single instance is to be created. You should instead rely on variables accessible through a shared scope (closure).
(function(window)(
var cache = {}, mylib;
window.mylib = mylib = {
cache: function(key, selector) {
cache[key] = selector;
return mylib;
}
}
})(window);
Update
And by the way, do not follow the jQuery pattern without having a real reason to do so ;)
Update
A better approach for PrivateSpace could be
function PrivateSpace(){
var cache = {};
return {
cache: {
get: function(key){
return cache[key];
},
set: function(key, value) {
cache[key] = value;
}
},
init: function() {
...
}
};
}
This is the pattern normally used for providing private members..
The prototype pattern does not allow per-instance private variables.
You can either use a private cache that will be accessed by all instances of PrivateSpace (by declaring the cache inside your outer most closure, or stop using the prototype pattern.