My question is, if it is better the use classes in Node.js or the function, or prototypes and modules, I know that most use the modules and function prototypes, but which is better?
And we most consider that classes have always been in all programming languages the best option to work.
classes vs. modules is the wrong question
The question you are looking for is classes vs. prototypes.
Both classes and prototypes are used by modules.
Modules (ES2015 Modules) are what JavaScript uses to be able to export and import code. Before JavaScript officially implemented modules there were hacks to do this and create code encapsulation which fixed issues such as pollution of the global scope; Immediately Invoked Function Expressions is an example. Node.js with CommonJS and Angular with AMD and several others tried to figure out how to do this in a better way and implemented their own 'module' system. I would like to think ES2015 Modules were influenced by other languages and CommonJS/Amd etc. and as a result, we now have a module system in JavaScript.
As for classes, they themselves create code encapsulation, but they cannot export themselves, that's what modules do. The same applies for the prototype based code, it creates code encapsulation but cannot export it self just like classes.
Now to put this together.
Example of a module, this example has nothing to do with classes or prototypes, only-a-module.js:
const privateHello = 'hello' // <- module code (private)
export const publicHello = 'hello'; // <- module code (public)
Example of a module that uses a class, module-that-exports-a-class.js:
export class Classes { // <- module AND class code (public)
private privateHello = 'hello'; // <- class code (private)
public publicHello = 'hello'; // <- class code (public)
} // <- class code (public)
const anotherPrivateHello = 'hello'; // <- module code (private)
export const anotherPublicHello = 'hello'; // <- module code (public)
Example of a module that uses prototypes, module-that-exports-a-prototype.js:
export function Prototypes() { // <- module AND prototype code (public)
const privateHello = 'hello'; // <- prototype code (private)
this.publicHello = 'hello'; // <- prototype code (public)
} // <- prototype code (public)
const anotherPrivateHello = 'hello'; // <- module code (private)
export const anotherPublicHello = 'hello'; // <- module code (public)
What makes this confusing to beginners coming from OOP languages is that for example in Java a class file (file.class) is automatically exported as a class, this is by default as this is how Java works. This is not the case in JavaScript. You must state what you are exporting.
Classes are an attempt to implement so called classical inheritance while prototype is, you guessed it, prototypal inheritance. These are two ways to deal with code-reuse and objects that keep their own state.
If we want to make things even more complicated, a good followup question is OOP vs. functional programming. But you can read that up in other places.
My question is if it is better the use classes in nodejs or the function or prototypes and modules, i know that most use the modules and function prototypes, but which is better?
Your question seems a bit misguided. In node.js, one does not choose between classes, prototypes and modules.
First off classes in Javascript uses the prototype. The class syntax is just syntactical sugar for defining a constructor and methods on the prototype. When you use the class syntax, you are creating a constructor with a prototype and causing methods to be added to the prototype (under the covers). So, there is no tradeoff between using classes and using the prototype.
The only tradeoff there is there is between using the new class syntax to define your prototype vs. doing it the older, manual way.
Then, classes are pretty much orthogonal to modules. You use modules when you want to encapsulate a body of code in a module interface so you can reap all the benefits of using modules (easier sharing, reuse, documenting, testing, etc...). That module interface can be whatever you think is most appropriate for your circumstance. You can export a series of plain functions. You can export one or more object constructors. You can export factory functions that create objects for you that you can then use methods on. The module scheme is massively flexible so you can export pretty much any type of interface you want (and classes can be a part of that if you choose).
There is no "best" way to export things from modules because it depends upon your needs, your chosen architectural and coding style, etc...
Related
While trying to organize the code of my first NodeJS-express project, I ran into some doubts about the use of namespaces, modules and classes. When to choose one? When another?
For example, my project is structured (simplifying) in.
routers -> controllers -> services -> repositories.
The possibilities I thought of to manage these "entities" are the following:
Classes
Classes with static methods
Singletons
Simple module export
Namespaces
Classes
I thought of avoiding them right away, since the above-mentioned entities do not need to memorize any state. Furthermore, they would complicate the code due to the need to be instantiated.
Classes with static methods
They are correct? Or rather a simple namespace or simple export of the modules?
Class + Singletons
A way of organizing the code in a "nicer" way than the simple class, but which does not convince me, since reading on the net that the singleton in TypeScript is replaceable with the namespace.
Simple module export
The way I thought to implement immediately, for example in this way (file user.repository.ts):
const add = async (user: User): Promise<void> => {
if(await canBeAdded(user)) {
//save user;
} else {
// throw error
}
}
export const UserRepository = {
add
}
It's corrects? Or am I not properly using what TypeScript offers? Being the first time I use this language, I would like to be sure I chose the right path.
Namespaces
Are they a better choice to develop the code published above? Are you advised against?
Thank you in advance for the answers! Any advice is welcome!
P.S. I know that, once the TypeScript is compiled, in Javascript the classes are practically syntactic sugar. What I'm interested in knowing are the best practices for writing good code in TypeScript.
I'm doing this Ensime package for Atom.io https://github.com/ensime/ensime-atom and I've been thinking about the possibility to use scala.js instead of writing Coffeescript.
Atom is a web based editor which is scripted with js and is node.js based. A plugin/package defines it's main entry point by pointing out a javascript object with a few specific.
I figured I should start out simple and try using scala.js replacing the simplest coffeescript file I have:
{View} = require 'atom-space-pen-views'
# View for the little status messages down there where messages from Ensime server can be shown
module.exports =
class StatusbarView extends View
#content: ->
#div class: 'ensime-status inline-block'
initialize: ->
serialize: ->
init: ->
#attach()
attach: =>
statusbar = document.querySelector('status-bar')
statusbar?.addLeftTile {item: this}
setText: (text) =>
#text("Ensime: #{text}").show()
destroy: ->
#detach()
As you can see this exports a require.js module and is a class extending a class fetched with require as well.
Sooo.
I'm thinking I'd just use Dynamic for the require dep as I've seen on SO How to invoke nodejs modules from scala.js?:
import js.Dynamic.{global => g}
import js.DynamicImplicits._
private[views] object SpacePen {
private val spacePenViews = require("atom-space-pen-views")
val view = spacePenViews.view
}
But if I wanted to type the super-class, could I just make a facade-trait and do asInstanceOf?
Secondly, I wonder how I can export my class as a node module. I found this:
https://github.com/rockymadden/scala-node/blob/master/main/src/main/coffeescript/example.coffee
Is this the right way? Do I need to do the sandboxing? Couldn't I just get moduleimported from global and write module.exports = _some_scala_object_?
I'm also wondering how I could extend existing js classes. The same problem as asked here, but I don't really understand the answer:
https://groups.google.com/forum/#!topic/scala-js/l0gSOSiqubs
My code so far:
private[views] object SpacePen {
private val spacePenViews = js.Dynamic.global.require("atom-space-pen-views")
type View = spacePenViews.view
}
class StatusBarView extends SpacePen.View {
override def content =
super.div()
}
gives me compile errors that I can't extend sealed trait Dynamic. Of course.
Any pointers highly appreciated!
I'm not particularly expert in Node per se, but to answer your first question, yes -- if you have a pointer to a JS object, and you know the details of its type, you can pretty much always define a facade trait and asInstanceOf to use it. That ought to work.
As for the last bit, you basically can't extend JS classes in Scala.js -- it just doesn't work. The way most of us get around that is by defining implicit classes, or using implicit def's, to get the appearance of extending without actually doing so.
For example, given JS class Foo, I can write
implicit class RichFoo(foo:Foo) {
def method1() = { ... }
}
This is actually a wrapper around Foo, but calling code can simply call foo.method1() without worrying about that detail.
You can see this approach in action very heavily in jquery-facade, particularly in the relationship between JQuery (the pure facade), JQueryTyped (some tweaked methods over JQuery to make them work better in Scala), and JQueryExtensions (some higher-level functions built around JQuery). These are held together using implicit def's in package.scala. As far as calling code is concerned, all of these simply look like methods on JQuery.
In case of utility module, I can have either class with static methods or just export methods. I think the first solution is better, though I saw a lot of implementations with second option. Are there any "nuances" here which I am not considering?
I would argue that a class with static methods is better for the following reasons:
If your class name is Utils, all imports will by default import it as Utils too. With exported functions however, they could be imported as Utils yet that would only be a convention , one that likely won't be the case in all the different places.
A class named Utils in a file named utils.js with all the utility methods neatly grouped together is aesthetically more pleasant than flat functions defined all over the place.
A class could have properties that are used among its methods, for this you'd need #babel/plugin-proposal-class-properties though. Again, much nicer than variables defined all over the place.
Exporting methods is safer because you don't give access to class properties. Note also that in javascrpt the concept of class does not have a lot of sense, it's been introduced to make feel more confortable developers with oo languages background. Try to work with Object prototyping instead.
A couple options I can think of, if the methods are intended to be a utility method on another class, you could use handbaked mixins: http://coffeescriptcookbook.com/chapters/classes_and_objects/mixins or rely on something similar in underscore/lowdash
If you want the encapsulation of methods and still have the ability to extend, you can do this:
class Foo
foo = -> alert 'foo'
#static: -> foo()
Foo.static() #=> 'foo'
Foo.foo #=> undefined
new Foo().foo #=> undefined
class Bar extends Foo
Bar.static() # => 'foo'
jsfiddle: http://jsfiddle.net/4ne7ccxk/
I'm starting out a long term project, based on Node.js, and so I'm looking to build upon a solid dependency injection (DI) system.
Although Node.js at its core implies using simple module require()s for wiring components, I find this approach not best suited for a large project (e.g. requiring modules in each file is not that maintainable, testable or dynamic).
Now, I'd done my bits of research before posting this question and I've found out some interesting DI libraries for Node.js (see wire.js and dependable.js).
However, for maximal simplicity and minimal repetition I've come up with my own proposition of implementing DI:
You have a module, di.js, which acts as the container and is initialized by pointing to a JSON file storing a map of dependency names and their respective .js files.
This already provides a dynamic nature to the DI, as you may easily swap test/development dependencies.
The container can return dependencies by using an inject() function, which finds the dependency mapping and calls require() with it.
For simplicity, the module is assigned to a global variable, i.e. global.$di, so that any file in the project may use the container/injector by calling $di.inject().
Here's the gist of the implementation:
File di.js
module.exports = function(path) {
this.deps = require(path);
return {
inject: function(name) {
if (!deps[name])
throw new Error('dependency "' + name + '" isn\'t registered');
return require(deps[name]);
}
};
};
Dependency map JSON file
{
"vehicle": "lib/jetpack",
"fuel": "lib/benzine",
"octane": "lib/octane98"
}
Initialize the $di in the main JavaScript file, according to development/test mode:
var path = 'dep-map-' + process.env.NODE_ENV + '.json;
$di = require('di')(path);
Use it in some file:
var vehicle = $di.inject('vehicle');
vehicle.go();
So far, the only problem I could think of using this approach is the global variable $di.
Supposedly, global variables are a bad practice, but it seems to me like I'm saving a lot of repetition for the cost of a single global variable.
What can be suggested against my proposal?
Overall this approach sounds fine to me.
The way global variables work in Node.js is that when you declare a variable without the var keyword, and it gets added to the global object which is shared between all modules. You can also explicitly use global.varname. Example:
vehicle = "jetpack"
fuel = "benzine"
console.log(vehicle) // "jetpack"
console.log(global.fuel) // "benzine"
Variables declared with var will only be local to the module.
var vehicle = "car"
console.log(vehicle) // "car"
console.log(global.vehicle) // "jetpack"
So in your code if you are doing $di = require('di')(path) (without var), then you should be able to use it in other modules without any issues. Using global.$di might make the code more readable.
Your approach is a clear and simple one which is good. Whether you have a global variable or require your module every time is not important.
Regarding testability it allows you to replace your modules with mocks. For unit testing you should add a function that makes it easy for you to apply different mocks for each test. Something that extends your dependency map temporarily.
For further reading I can recommend a great blog article on dependency injection in Node.js as well as a talk on the future dependency injector of angular.js which is designed by some serious masterminds.
BTW, you might be interested in Fire Up! which is a dependency injection container I implemented.
I'm refactoring a large javascript codebase to use RequireJS. Unfortunately, many of the files I'm dealing with are not object-oriented, and cannot return an object without significant modification. Is there a more efficient way to give 'dependent' modules access to the functions and variables contained in a module (without returning an object) ?
I have read about using the exports syntax for defining modules, but it is very unclear whether that would be a valid solution for this situation.
In a defined module, the exports object is what gets exported from the module and passed to whatever module requires it.
Consider this:
define(["exports"], function(exports){
exports.myCustomFunction = function(){};
exports.myCustomObject = {};
exports.myCustomVariable = true;
})
This module will place all the disparate functions and/or objects that you want made public onto the exports object.
At this point RequireJS will use that exports object to pass to a module that requires it:
require(["nameOfCustomModule|filename"], function(myCustomModule){
//evaluates to true
console.log(myCustomModule.myCustomVariable);
})
Here's a simple fiddle. Just bring up your console and you will see the value logged there. http://jsfiddle.net/xeucv/
Hope this clears it up a bit!