Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
The community reviewed whether to reopen this question 10 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm kind of new in programming and I'm currently wondering myself what is the benefit of class vs a simple "list" of related functions in NodeJs.
As very simplified example, I guess I would create a user like this if I'd use Class:
class User {
constructor(email) {
this.email = email;
}
validateEmail() {
// whatever function that checks if this.email is valid
if (this.email === 'notValid') {
throw new Error();
}
return this;
}
create() {
this.validateEmail();
// whatever function that inserts user in the database
return user;
}
}
const newUser = new User('test#test.com');
const user = newUser.create();
And I would do something like this with what I call a "list" of related functions :
const validateEmail = email => {
// whatever function that checks if valid email
if (email === 'notValid') {
throw new Error();
}
return true;
};
const createUser = email => {
if (validateEmail(email)) {
// whatever function that inserts the user in the database
return user;
}
};
const user = createUser('test#test.com');
The second way seems to me that it can ends with a little less code. And don't even have to instatiate the class.
Let's say I have a node API, with multiple "User" routes and controllers. I guess I have to instantiate the User Class every time a User routes/controllers is called, right ? As a beginner, this does not sound "optimized" to me... But I'm surely missing something...
Thank for your help
Classes tie data (properties on this, the instance) to functionality (functions on the internal prototype of every instance).
If you don't ever have data that makes sense to be associated with an instance, there's not much point in having a class. Here, you do have data (the email string) and a related function (validateEmail), so a class is a possible option, though it's much better when there are more properties and more functions involved. (If there's only one property, and the property is only there so it can be called with that one function, a class does indeed seem unnecessarily verbose.)
One benefit of such a class is that, once you have an instance, you can pass that instance around to any other module (or scope), and that module can call functions related to the instance, without having to import the equivalent standalone function. For example, imagine if the consumer of your User class was in a different module, and the consumer wants to be able to create users and validate them. Then, the module that exports the bulk of the User code would either have to
(1) Export many standalone functions (which could get a bit tedious and hard to manage), or
(2) Export only a class
Being able to export just a Class and have any users of the class or its instances use class-related methods is quite handy - that way, you don't have to pass around multiple values every time you need to use a User-related function.
Imagine if module A needs to be able to create a user, module B needs to be able to verify a user, and module C needs to be able to check to see if a user has been verified or not yet. If the main User file created and exported standalone functions for each of these things, and each consuming module imported what they needed to call, things would be a bit ugly. But if the main User file created and exported a Class, it would be trivial: the creator of a User (module A) would import the class, instantiate an object const user = new User('a#a.com'), and pass it along to module B, which could then call user.validateEmail() (no imports necessary). Then eventually the user instance gets passed along to module C, which calls user.checkIfUserIsValidated() (again, no imports necessary).
With the Class method, having an object which has both instance data and related functions on the same object (the class instance) can make code a lot cleaner.
Of course, you don't ever have to use a class if you don't want to, but that's one possible benefit.
With the example you have given, you indeed have a point:
a function that validates an email does not really need an instantiated object to act on, and in fact you want to run it before creating the API's object instance.
a function that really returns a different object (user is not an instance of User) without mutating the this object, is also not the best reason for a separate class. If this (email verification) is all you will ever need to do as "extra" compared to the API's object class you already have access to (which returns user), then the second way is fine.
If however, you will have several other functionalities you want to extend that API with, like there could be:
preparing a personalised email for which you would need their name, address, email, gender,...
returning some calculated score based on several properties (age, last login date, access level, ...)
...
...then it might become nicer to use the first pattern -- although still a matter of opinion.
I would suggest to still create your own class, but to let it create the API's object immediately, and make the returned object value a property of your own instance. This new object is then a composition of the API's interface with your own extensions to it.
Maybe like so:
function validateEmail(email) {
// whatever function that checks if an email is valid
if (email === 'notValid') {
throw new Error();
}
}
class User {
constructor(email) {
this.rank = 10; // Let's say you need this property that is not offered by the API
validateEmail(email);
// whatever function that inserts user in the database
this.apiUser = api.createUser(email);
}
promote() { // Some function using the new properties
if (this.rank > 1) this.rank--;
}
prepareEmail() { // Other function using a mix
return {
sentBy: "admin#mysite.com",
to: this.apiUser.get("email"),
body: `Dear ${this.apiUser.get("name")}, your current rank is ${this.rank}`
};
}
}
const user = new User('test#test.com');
So, here you see that the main code creates one object instance. The API's object instance is encapsulated inside it. You could either allow the caller to work directly with the API, using user.apiUser.someApiMember syntax, or you could create your own wrapper functions in your own class, to be accessed as user.myApiWrapperMember.
Related
I understand that there is a concept of Action Filters in languages like C# using ASP.NET. I would like to have this kind of pre-processing functionality in my class methods, using Javascript. Is this possible/a part of the language? Otherwise how would I implement this feature? It sounds like a language level implementation, like constructors and getters, and so I'm confused whether or not it's possible to implement such a thing.
TMI: I'm trying to create an ecommerce website with firebase auth. Right now I have implemented all the cart methods; but I would like to have some sort of auth check to allow these methods to be called, or otherwise route the user to the login page.
While I couldn't find the exact functionality of an Action Filter, JS has a neat feature called Proxy's, which can be used for the same purpose.
When you create a proxy of an object, it intercept the requests to the given object, and sort of acts like an intermediary. What I found is that you can include the processing logic of an Action Filter, such as checking if a user is authorized, inside the get and set of the handler provided to the proxy.
const baseInstance = new SomeClass(param1, param2);
const handler = {
get(target, prop) {
if(/* implement required check */) alternatePath();
else return target[prop];
},
};
const extendedInstance = new Proxy(baseInstance, handler);
This eliminates the need to modify each method of the base class, just to include that one check(or multiple checks; that can also be done). Doing so, we separate the functionalities.
Check out this neat video for more info.
I have a class I reuse, often, to the tune of possibly tens of thousands of instances in a given session. It occurred to me that creating all these properties within the constructor may be replication, that is each function is unique in memory and not a pointer, so I created a little test setup:
const testTree = function (){
console.log(this, this.konnichiwa);
}
const testFjord = function (aloha){
return function() {
console.log(this, aloha, this.konnichiwa);
}
}
class Clown extends Object{
constructor(props){
super(props);
const aloha = "Hello!"; //<- Private party
this.konnichiwa = "Also hello I think"; //<- Everyone's invited
this.testWan = () => {
console.log(this, aloha, this.konnichiwa);
}
this.testTree = testTree;
this.testFjord = testFjord(aloha);
}
testToo = () => {
console.log(this, this.konnichiwa);
}
}
//export default Clown; //this is an export in my application, used lots
const test = new Clown();
const otherTest = new Clown();
console.log(test.testWan === otherTest.testWan);
console.log(test.testToo === otherTest.testToo);
console.log(test.testTree === otherTest.testTree);
console.log(test.testFjord === otherTest.testFjord);
test.testWan();
test.testToo();
test.testTree();
test.testFjord();
Part 1
As you can test above, testWan, testToo, and testFjord are all unique per instance, but testTree is not. Is there any way to declare a "pointer"/"reusable function" but inside class constructor?
The issue here with testToo and testTree is that they can't access private vars within the constructor like testWan can. testFjord is a factory and can be passed these, but then the returned function is unique and won't be able to interact well with vars passed into it.
It's very likely not possible - I think it's a catch 22 scope thing - but you may know better. The only recourse I can think of is to add a property to this for each thing I need to use in testTree, but that exposes things I may not want exposed outside of the class.
Part 2
This part only applies if this is a generally consistent behavior, and not something completely unique per-browser. Does the engine hold onto references to things like conditionals (which I suspect are sorta anonymous-function-like behind the scenes) once the constructor has run?
I have a fairly knarly conditional setup I'm not going to shove in the code here. This is entirely within the constructor right now. I suspect that, although not a function declaration itself, it is also not a pointer, but an entirely fresh instance per the 'new' in new Clown. It needs to manipulate some private vars and so per Part 1 I haven't figured out a good way to extract this.
Example, there are references to private vars inside the constructor for exposed functions: aloha above is private but used by public testWan function, and so needs to be held after constructor has executed. Is the entire constructor held for the life of test & otherTest or is the constructor going to be dropped after use and just the reference to aloha held in memory?
I'm a fan of Vue which a try to use on some occasions. Anyway, there is something I always found not so handy with it: reactivity lies within $data. Well not always, as external data can be tracked by Vue, as in computed properties, in templates… But I found this way uncomfortable and not always consistent (see another question about it, here Reactivity on Variables Not Associated With Data, Computed, etc). So my decision now is use $data as the main source of reactivity and stop trying to find other ways.
However, reactivity within $data poses me a problem in what is a common case for me: many pieces of data here and there in other imported objects. This makes even more sense as I consider Vue as the View end not the business logic. Those imported objects are sometimes complex and within Vue components, I found no way to cherry pick pieces of information and kind of ask Vue to bind to them. The only way was to declare entire objects in the $data section which makes tracking very heavy: loads of setters/getters when only one would be enough in a simple component, for example.
So I designed a class called 'Reactor' whose instances role is to install getter/setters on any piece data of my wish in a complex object (or more than one). Those instances are imported into Vue components and then $watchers of Reactor instances have properties which can contain as many functions as I wish which are called when pieces of data are altered through the Reactor. To make things simple by default is filled with the same property name as the data it bounds to. This precisely those function which will update $data when external data change.
class Reactor {
constructor() {
this.$watchers = {};
}
addProperty(originalObject, keyString, aliasKeyString) {
if(aliasKeyString === undefined) {
aliasKeyString = keyString;
}
if(this[aliasKeyString] !== undefined || originalObject[keyString] === undefined) {
const errorMessage = `Reactor: cannot add property '${aliasKeyString}'!`;
console.error(errorMessage);
throw errorMessage;
}
this.$watchers[aliasKeyString] = [];
Object.defineProperty(this, aliasKeyString, {
set(newValue) {
const oldValue = originalObject[keyString];
originalObject[keyString] = newValue;
this.$watchers[aliasKeyString].forEach((f) => {
if(typeof f === "function") {
f(newValue, oldValue, aliasKeyString);
}
});
},
get() {
return originalObject[keyString];
},
});
}
}
An example can be seen in the codepen here: https://codepen.io/Djee/pen/gyVZMG
So it's sort of an 'inverted' Vue which allows updating $data on external conditions.
This pattern also helped me resolve a case which was rather difficult before: have a double-bind on an input with a filter in-between which will set the input and its attached external value straight upon #change event only. This can be seen in the same codepen given above.
I was a little surprised to have found nothing taking this in charge in Vue itself. Did I miss something obvious? This is mainly the purpose of this somewhat long introduction. I had no time to check whether Vuex would solve this nicely.
Thanks for any comments as well.
Export Objects {} vs Export function
I'm developing an exercise application, I came across to the question When do I need to exports an object {} instead of a function class?
Scenario example:
I'm building a simple authentication module using the object style.
// file auth.js
module.exports = {
login: function() {
// code login
},
logout: function() {
// code logout
},
register: function() {
// code register
}
}
Here I'm using the anonymous function style
module.exports = function() {
return {
login: function() {
// code login
},
logout: function() {
// code logout
},
register: function() {
// code register
}
}
}
Requiring
When I want to require this module I just do:
var auth = require('auth');
auth.login(); // trigger login function via object
auth().login() // trigger login function via function
It will work with both the approaches, but I'm confused to choose which fit better and why.
Questions
How do you understand in your design of a module, when is appropriate to exports, an object, anonymous function, named function to Instantiate?
Which are the difference and how the require method behave, when requiring these functions or Objects ?
How do you understand in your design of a module, when is appropriate to exports, an object, anonymous function, named function to Instantiate?
true minimalists aim to export a single function if that will suffice. This is based on the scope of your module and assumes a small and focused purpose.
Export an object of related functions when you need a set of functions to have a meaningful set of functionality. For example, a tempConversion module might have both cToF and fToC functions.
If you are doing OO, exporting the constructor function is fine.
a closure function that returns the real payload (which can be an object or a function) is useful for configuration options. For example var tip = require('computeTip')(18); could store 18 in closure and return a function that would calculate 18% tip when called with a number.
Here's a rule of thumb: if you export only one named function a la require('average').average(listOfNumbers), it's redundant, so just export the average function directly to make it more concise. If you have more than one function you want to expose, use an object whose properties are the functions.
Which are the difference and how the require method behave, when requiring these functions or Objects ?
There are no differences. require has a single behavior that accommodates each of these techniques.
In both your examples you actually return an object and not a function class. In the second case you get the object by executing the function. In order to use the function as a class you should return a function which acts as the constructor, and then instantiate with the new operator.
That being said, I would prefer an object over a class if I consider my module as a singleton, something that would be common to every file that would include it. An example would be a module that implements a common access layer to my database.
A class makes more sense if you intent to instantiate it multiple times. An example would be a specific model class for your database schema, like a User class.
// Main class
function App() {
this.task = new Task(this); // pass the instance of this class to Task so
// it has access to doSomething
}
App.prototype.doSomething = function () {
alert("I do something that Task() needs to be able to do!");
};
function Task(app) {
// This class needs access to App()'s doSomething method
this.appInstance = app;
this.appInstance.doSomething(); // Great, now Task can call the method
}
var app = new App();
The aim of the code above is to give Task access to one of App's methods called doSomething. The code is the current way I'd go about it and I'm posting this to see if it's the best way...
To give Task access I simply pass the whole instance of App, is this efficient or is there a better way to go about it? Is the code above general practice in going about doing something like this?
Yes, what you have is fine. It is a circular dependency, however because of JavaScript's dynamic nature there aren't really any issues.
Another way you could reference App from Task would be a Singleton pattern or something similar, but that would probably be harder to test.
jsFiddle Demo
Generally bind would be used in this scenario assuming that the Task "class" didn't also setup other facilities which were not shown here.
Bind allows for the context to be provided for a function. This could be done in app's constructor. At which point only a function task would be required to call "someMethod".
function task(){
return this["someMethod"]();
}
function App(){
task.bind(this)();
}
App.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
However, if task must be a "class", and have other responsibilities then the prototype function could be shared.
function Task(){}
function App(){}
App.prototype.someMethod = Task.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
a.task();//->"Task needed access to this"
var t = new Task();
t.someMethod();//->"Task needed access to this"
Your app instances and task instances are tightly bound. App instances have tasks and this can be fine.
A design of loosely coupled objects is more flexible and easier to extend but more complicated to initially create. One such pattern is using a mediator/publish subscriber and have app raise an event/publish message any other object function can listen to this and take action on the event.
For example: your app creates an Ajax instance and when that instance is done it raises some event (fetchedData for example). A listener could be DomDependent.updateView function but later you may want to add/remove/change the order of tasks to do after data is fetched. This can all be configured in a app.init function or per procedure in a controller that kicks of certain procedures (like log in, search, ...).
Instead of creating a whole bunch of specific functions in Ajax (fetchUserPrefs, login, search, ...) you can create one general function and have the controller add listeners or pass the next event when fetchData is complete to run the correct next function.
Here is some pseudo code:
var app = {
init:function(){
mediator.add("updateLogin",domDependent.updateView);
mediator.add("updateLogin",app.loadUserPrefs);
mediator.add("failLogin",domDependent.updateView);
},
login: function(){
mediator.trigger("loadingSometing",{type:"login"});
ajax.fetch({
onComplete:"updateLogin",//what listens to updateLogin you decided in init
onFail:"failLogin",
loginDetails:domDependent.getLogin(),
url:settings.loginUrl,
type:"post"
});
}
}
var ajax = {
fetch:function(data){
data = data || {};
//simple check for onComplete, it's mandatory
var complete = data.onComplete || app.raiseError("ajax.fetch needs onComplete");
//other code to validate data and making ajax request
onSuccess:function(resp){
//mutate data object as the mediator will pass it to
// whatever other function is called next
// you don't hard code domDependent.updateView and
// app.loadUserPrefs because fetch can be used generally and
// success may have to do completely different things after its done
// and you want to define procedures in init, not all over your code
data.response=resp;
//trigger event to do whatever needs to be done next
mediator.trigger(complete,data);
}
}
}
As you can see it gets complicated and maybe doesn't look like code you're used to but it's highly configurable.
I may have misunderstood the advantages of the mediator pattern to loose couple and if so please comment. I use it to:
Make methods more general instead of copying a lot of logic only
because what to do after it's done is different. In fetch the ajax
object just fetches, this would be the same for login or getting
user preferences, the only thing different is what function to call
next/on error when it's done.
A procedure like login involves multiple functions in multiple
objects if this function chain hard code what to do next once a
particular function is done your procedure of login is defined all
over your code. When defining it in init/config you can easily change the
order or add/remove functions in the chain.