Basic concepts
Inna Ivashchuk
Senior Software Engineer
JS developer, music fan, movie-dependent and Star Wars fan 🤓
May the Force be with you!
Global objects
REPL. File execution
What will happen when you type the following code in a browser console?
// console.log(this) or just
this
And the correct answer is - we will get the full global object Window
And some examples:
// standard way to use console.log
console.log('hello');
// equal to
window.console.log('hello');
// custorm variable created like that
window.myVar = 'JavaScript';
// we can access like that
console.log(myVar);
There is no global object window, but we have - global namespace Object
// standard way to use console.log
console.log('hello');
// equal to
global.console.log('hello');
// custorm variable created like that
global.myVar = 'JavaScript';
// we will get 'undefined'
console.log(myVar);
// this is pointing to the global
console.log(this);
// common functions
global.require('http'); // equal to - require('http');
global.process; // equal to - process;
global.setImmediate(cb); // equal to - setImmediate(cb);
Commonly used:
In the Node.js module system, each file is treated as a separate module
const circle = require('./circle.js');
console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);
Here are the contents of circle.js:
const { PI } = Math;
exports.area = (r) => PI * r ** 2;
exports.circumference = (r) => 2 * PI * r;
Module 1
Module 2
Module 3
Variables local to the module will be private because the module is wrapped in a function by Node.js (IIFE).
app.js
Every file is a module.
Every variable and function defined in the file are in the scope of this module and not available outside.
logger.js
const loggerUrl = 'http://mylogger.io/log';
function logger(message) {
// Send an HTTP request
console.log(message);
}
module.exports.log = logger;
// we can export URL as well
// mostly should not be done,
// as it's implementation details
module.exports.LOGGER_URL = loggerUrl;
app.js
const logger = require('./logger');
function app() {
// some logic can be there
logger.log('log my message');
}
app();
const logger = require('./logger');
function app() {
// some logic can be there
logger('log my message');
}
app();
const loggerUrl = 'http://mylogger.io/log';
function logger(message) {
// Send an HTTP request
console.log(message);
}
module.exports = logger;
The module.exports property can be assigned a new value (such as a function or object).
const Square = require('./square.js');
const mySquare = new Square(2);
console.log(`The area of mySquare is ${mySquare.area()}`);
The square module is defined in square.js:
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
a.js
b.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
   When main.js loads a.js, then a.js, in turn, loads b.js. At that point, b.js tries to load a.js. In order to prevent an infinite loop, an unfinished copy of the a.js exports object is returned to the b.js module. b.js then finishes loading, and its exports object is provided to the a.js module.
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true
addTwo.mjs
app.mjs
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
// app.mjs
import { addTwo } from './addTwo.mjs';
// Prints: 6
console.log(addTwo(4));
Available from NodeJS v.12.12.0
The assert module provides a set of assertion functions for verifying invariants.
const assert = require('assert/strict');
// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// {
// + a: 1
// - a: '1'
// }
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(typeof 123 === 'string')
The util module supports the needs of Node.js internal APIs. Many of the utilities are useful for application and module developers as well.
const util = require('util');
const fs = require('fs');
const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
// Do something with `stats`
}).catch((error) => {
// Handle the error.
});
util.format('%s:%s', 'foo', 'bar', 'baz');
// Returns: 'foo:bar baz'
util.types.isDate(new Date()); // Returns true
The path module provides utilities for working with file and directory paths.
const path = require('path');
path.parse('/home/user/dir/file.txt');
// Returns:
// { root: '/',
// dir: '/home/user/dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file' }
path.format({
root: '/ignored',
dir: '/home/user/dir',
base: 'file.txt'
});
// Returns: '/home/user/dir/file.txt'
path.resolve('/foo/bar', './baz');
// Returns: '/foo/bar/baz'
The process object is a global that provides information about, and control over, the current Node.js process.
const process = require('process');
// print process.argv
process.argv.forEach((val, index) => {
console.log(`${index}: ${val}`);
});
process.on('uncaughtException', (err, origin) => {
fs.writeSync(
process.stderr.fd,
`Caught exception: ${err}\n` +
`Exception origin: ${origin}`
);
});
process.on('exit', (code) => {
console.log('Process exit event with code: ', code);
});
process.exit(1);
The fs module enables interacting with the file system.
const { unlink } = require('fs/promises');
(async function(path) {
try {
await unlink(path);
console.log(`successfully deleted ${path}`);
} catch (error) {
console.error('there was an error:', error.message);
}
})('/tmp/hello');
const { unlinkSync } = require('fs');
try {
unlinkSync('/tmp/hello');
console.log('successfully deleted /tmp/hello');
} catch (err) {
// handle the error
}
Synchronous example:
HTTP server
const http = require('http');
// Create an HTTP server
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
server.listen(8000);
const http = require('http');
http.get('http://localhost:3000', { agent }, (res) => {
res.on('data', (data) => {
// Do nothing
});
});
HTTP request
Read-Eval-Print Loop
Read-Eval-Print Loop is the Node.js interactive shell; any valid JavaScript written in a script can be passed to the REPL.
It can be extremely useful for experimenting with Node.js, debugging code, and figuring out some of JavaScript's more eccentric behaviors.
Starting the REPL is simple - just run node on the command line without a filename.
$ node
> var x = "Hello, World!"
undefined
> x
"Hello, World!"
> .exit
$ node
And now is time to play:
The following special commands are supported by all REPL instances (from Node.js REPL docs:
> .editor
# Entering editor mode (<ctrl>-D to finish, <ctrl>-C to cancel)
function welcome(name) {
return `Hello ${name}!`;
}
welcome('Node.js User');
# <ctrl>-D
'Hello Node.js User!'
>
 If you need to access any of the built-in modules, or any third-party modules, they can be accessed with require, just like in the rest of Node.
For example:
$ node
> path = require('path')
{ resolve: [Function],
normalize: [Function],
join: [Function],
dirname: [Function],
basename: [Function],
extname: [Function],
exists: [Function],
existsSync: [Function] }
> path.basename("/a/b/c.txt")
'c.txt'
Create a new directory tutorial2
Create next modules: main.js, file.js, logger.js (or you can turn on your imagination and create something different)
Create 2 text files and read them in file.js using fs
Create a logger module, that should print error or info messages to the terminal
In a main.js create a simple HTTP server, that can read URLsÂ
Use logger and file modules in main.js
Use functions from global in modulesÂ