125

According to the Node.js manual:

If you want the root of your module's export to be a function (such as a constructor) or if you want to export a complete object in one assignment instead of building it one property at a time, assign it to module.exports instead of exports.

The example given is:

// file: square.js
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

and used like this:

var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

My question: why does the example not use square as an object? Is the following valid and does it make the example more "object oriented"?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());
Naresh
  • 23,937
  • 33
  • 132
  • 204
  • 1
    Your example is a syntax error. After renaming `square` to `Square` the `new square()` no longer exists. – Sukima Dec 12 '13 at 03:57
  • 3
    Sorry, that was a typo. Fixed it. My intention was to show Object/Function name starting with upper case and instance name starting with a lower case. – Naresh Dec 12 '13 at 04:25
  • 4
    I figured as much, That is why I wrote [my answer](http://stackoverflow.com/a/20534891/227176) the way I did. I just wanted to say that I'm really glad others look at modules in the same way. I often use the new keyword and organize my modules to export a single constructor function. I find it makes readability and conceptualization of solutions easier. I can tell at a glance what kind of construct I'm intending to use. Kudos for thinking like me ;) – Sukima Dec 12 '13 at 14:57

5 Answers5

179

CommonJS modules allow two ways to define exported properties. In either case you are returning an Object/Function. Because functions are first class citizens in JavaScript they to can act just like Objects (technically they are Objects). That said your question about using the new keywords has a simple answer: Yes. I'll illustrate...

Module exports

You can either use the exports variable provided to attach properties to it. Once required in another module those assign properties become available. Or you can assign an object to the module.exports property. In either case what is returned by require() is a reference to the value of module.exports.

A pseudo-code example of how a module is defined:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

})(theModule, theModule.exports, theRequireFunction);

In the example above module.exports and exports are the same object. The cool part is that you don't see any of that in your CommonJS modules as the whole system takes care of that for you all you need to know is there is a module object with an exports property and an exports variable that points to the same thing the module.exports does.

Require with constructors

Since you can attach a function directly to module.exports you can essentially return a function and like any function it could be managed as a constructor (That's in italics since the only difference between a function and a constructor in JavaScript is how you intend to use it. Technically there is no difference.)

So the following is perfectly good code and I personally encourage it:

// My module
function MyObject(bar) {
  this.bar = bar;
}

MyObject.prototype.foo = function foo() {
  console.log(this.bar);
};

module.exports = MyObject;

// In another module:
var MyObjectOrSomeCleverName = require("./my_object.js");
var my_obj_instance = new MyObjectOrSomeCleverName("foobar");
my_obj_instance.foo(); // => "foobar"

Require for non-constructors

Same thing goes for non-constructor like functions:

// My Module
exports.someFunction = function someFunction(msg) {
  console.log(msg);
}

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"
Sukima
  • 9,965
  • 3
  • 46
  • 60
  • 2
    Can I do require('./my-object.js')("foobar") for short? Or does the require('module')(params) syntax for a different use case? – Hampus Ahlgren Dec 17 '14 at 14:26
  • 1
    Nothing stopping you, It's all just JavaScript. So yes you can use the shorter syntax. – Sukima Dec 17 '14 at 21:51
  • 3
    The pseudo-code example of how a module is defined has completely cleared up my understanding of the Node.js module system. Thank you! – Nitax Feb 11 '16 at 03:24
137

In my opinion, some of the node.js examples are quite contrived.

You might expect to see something more like this in the real world

// square.js
function Square(width) {

  if (!(this instanceof Square)) {
    return new Square(width);
  }

  this.width = width;
};

Square.prototype.area = function area() {
  return Math.pow(this.width, 2);
};

module.exports = Square;

Usage

var Square = require("./square");

// you can use `new` keyword
var s = new Square(5);
s.area(); // 25

// or you can skip it!
var s2 = Square(10);
s2.area(); // 100

For the ES6 people

class Square {
  constructor(width) {
    this.width = width;
  }
  area() {
    return Math.pow(this.width, 2);
  }
}

export default Square;

Using it in ES6

import Square from "./square";
// ...

When using a class, you must use the new keyword to instatiate it. Everything else stays the same.

maček
  • 76,434
  • 37
  • 167
  • 198
  • 3
    Unusually concise structure! – Christophe Marois Jul 08 '14 at 15:58
  • 1
    So it seems like in your – Ada Richards Sep 13 '16 at 17:45
  • 2
    Questions I had and looked up, in case it's helpful to others: _Where are `import` and `export` defined?_ These are reserved keywords in ECMAScript 6 (ES6). Prior to ES6, one had to use libraries to manage modules. Node's moduling is modeled after the CommonJS library's Modules. _What is the `default` in `export default Square`?_ This specifies what to import when you just import the 'file' and not other, specific exports from that file. For as long as they exist, I found these pages helpful: https://spring.io/understanding/javascript-modules and http://exploringjs.com/es6/ch_modules.html – Ada Richards Sep 13 '16 at 18:42
1

This question doesn't really have anything to do with how require() works. Basically, whatever you set module.exports to in your module will be returned from the require() call for it.

This would be equivalent to:

var square = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

There is no need for the new keyword when calling square. You aren't returning the function instance itself from square, you are returning a new object at the end. Therefore, you can simply call this function directly.

For more intricate arguments around new, check this out: Is JavaScript's "new" keyword considered harmful?

Community
  • 1
  • 1
Brad
  • 159,648
  • 54
  • 349
  • 530
  • 3
    There is nothing wrong with using the new keyword. I hate all the FUD around it. – Sukima Dec 12 '13 at 03:58
  • 1
    @Sukima Agreed. :-D I'm pointing out why it doesn't matter in this case, and linked to the other question regarding `new` so others can participate in the war on it there. – Brad Dec 12 '13 at 03:59
0

The example code is:

in main

square(width,function (data)
{
   console.log(data.squareVal);
});

using the following may works

exports.square = function(width,callback)
{
     var aa = new Object();
     callback(aa.squareVal = width * width);    
}
AmirtharajCVijay
  • 1,078
  • 11
  • 12
0

At the end, Node is about Javascript. JS has several way to accomplished something, is the same thing to get an "constructor", the important thing is to return a function.

This way actually you are creating a new function, as we created using JS on Web Browser environment for example.

Personally i prefer the prototype approach, as Sukima suggested on this post: Node.js - use of module.exports as a constructor

Josue
  • 31
  • 5