Overriding util.format affects util.(other) - node.js

Exploring NodeJS..
BaseClass.js:
const util = require("util");
class BaseClass {
constructor() {
this.util = util;
this.init();
}
init() {
console.log( util.format( "%s", "baseclass format" ) );
console.log( util.isArray( [1,2,3] ) );
util.log( "baseclass log" );
}
}
module.exports = BaseClass;
SubClass.js:
const BaseClass = require("./BaseClass");
class SubClass extends BaseClass {
constructor() {
super();
}
init() {
this.util.format = function() { return "subclass format"; }
this.util.isArray = function() { return "subclass isArray"; }
this.util.log = function() { console.log( "subclass log" ); }
super.init();
}
}
new SubClass();
Output (of node SubClass.js):
subclass format
subclass format
subclass format
Hmm. Comment out util.format override in SubClass.js:
// this.util.format = function() { return "subclass format"; }
Try again. Output (of node SubClass.js):
baseclass format
subclass isArray
subclass log
Can someone tell me why this is happening? I'd've guessed that isArray and log call format within the util module but I'm not sure where to look to verify this. node_modules/node/index.d.ts isn't really enlightening me.

Your intuition is correct. The easiest place to verify this is the docs for console.log (emphasis mine):
console.log([data][, ...args])
Added in: v0.1.100
data <any>
...args <any>
Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).
In the Node.js source you can see where this happens in lib/console.js (line 140).
In your code, this.util is a reference to the object returned by require('util'), so when you replace this.util.format you're replacing it for all code, not just the code inside your class.

Related

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

Unable to use variable outside of class in the class

I am making a simple note taking app to learn node and ES6. I have 3 modules - App, NotesManager and Note. I am importing the Note class into the NotesManager and am trying to instantiate it in its addNote function. The problem is that even though the import is correct, it turns out to be undefined inside the class definition. A simpler solution would be to just instantiate the NotesManager class and add the Note class to its constructor however, I want to have NotesManager as a static utility class.
Here is my code.
Note.js
class Note {
constructor(title, body) {
this.title = title;
this.body = body;
}
}
module.exports = Note;
NotesManager.js
const note = require("./Note");
console.log("Note: ", note); //shows correctly
class NotesManager {
constructor() {}
static addNote(title, body) {
const note = new note(title, body); //Fails here as note is undefined
NotesManager.notes.push(note);
}
static getNote(title) {
if (title) {
console.log(`Getting Note: ${title}`);
} else {
console.log("Please provide a legit title");
}
}
static removeNote(title) {
if (title) {
console.log(`Removing Note: ${title}`);
} else {
console.log("Please provide a legit title");
}
}
static getAll() {
//console.log("Getting all notes ", NotesManager.notes, note);
}
}
NotesManager.notes = []; //Want notes to be a static variable
module.exports.NotesManager = NotesManager;
App.js
console.log("Starting App");
const fs = require("fs"),
_ = require("lodash"),
yargs = require("yargs"),
{ NotesManager } = require("./NotesManager");
console.log(NotesManager.getAll()); //works
const command = process.argv[2],
argv = yargs.argv;
console.log(argv);
switch (command) {
case "add":
const title = argv.title || "No title given";
const body = argv.body || "";
NotesManager.addNote(title, body); //Fails here
break;
case "list":
NotesManager.getAll();
break;
case "remove":
NotesManager.removeNote(argv.title);
break;
case "read":
NotesManager.getNote(argv.title);
break;
default:
notes.getAll();
break;
}
Is it possible for me to create a strict utility class which I can use without instantiating like in Java? Pretty new here and have tried searching for it without any luck. Thank you for your help.
When you do this:
const note = new note(title, body);
you redefine note shadowing the original note from the outer scope. You need to pick a different variable name.
Something like this should work better:
static addNote(title, body) {
const some_note = new note(title, body); //Fails here as note is undefined
NotesManager.notes.push(some_note);
}

passing function to a class in nodejs

I have a function that I need to pass to a class I have defined in nodeJs.
The use case scenario is I want to give the implementer of the class the control of what to do with the data received from createCall function. I don't mind if the method becomes a member function of the class. Any help would be appreciated.
//Function to pass. Defined by the person using the class in their project.
var someFunction = function(data){
console.log(data)
}
//And I have a class i.e. the library.
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall(){
var result = new Promise (function(resolve,reject) {
resolve(callApi());
});
//doesn't work. Keeps saying notificationHandler is not a function
result.then(function(resp) {
this.notificationHandler(resp);
}) ;
//I want to pass this resp back to the function I had passed in the
// constructor.
//How do I achieve this.
}
callApi(){ ...somecode... }
}
// The user creates an object of the class like this
var obj = new A("abc#gmail.com", someFunction);
obj.createCall(); // This call should execute the logic inside someFunction after the resp is received.
Arrow functions (if your Node version supports them) are convenient here:
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall() {
var result = new Promise(resolve => {
// we're fine here, `this` is the current A instance
resolve(this.callApi());
});
result.then(resp => {
this.notificationHandler(resp);
});
}
callApi() {
// Some code here...
}
}
Inside arrow functions, this refers to the context that defined such functions, in our case the current instance of A. The old school way (ECMA 5) would be:
createCall() {
// save current instance in a variable for further use
// inside callback functions
var self = this;
var result = new Promise(function(resolve) {
// here `this` is completely irrelevant;
// we need to use `self`
resolve(self.callApi());
});
result.then(function(resp) {
self.notificationHandler(resp);
});
}
Check here for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

ES6, PreloadJS and scope

In PreloadJS' callback functions I'm losing scope. Have tried different methods such as an arrow function (which aren't valid on the highest level etc... Any tips? (sorry for the malformed code block (class defenition etc), still getting used to this editor, trust me, all is working code)...
import Navigation from './Navigation'
import ajax from "./Ajax";
import Helper from "./Helper";
let preload = null;
export default class Page{
constructor(){
this.preload = new createjs.LoadQueue();
this.preload.addEventListener("fileprogress", this.handleFileProgress);
this.preload.addEventListener("fileload", this.handleFileComplete);
}
initPage(_arg = []){
this.buildPage(this.thePage);
}
buildPage(_content){
this.loadImage(item.featured_image_thumbnail_url);
}
handleFileComplete(event){
console.log(event);
console.log(this); // undefined
let el = document.getElementById('heroImage');
let loader = el.getElementsByClassName('loader')[0];
this.showPage(); // cannot read property showPage of undefined
}
// small arrow test, doesn't seem valid
//handleFileComplete = (event) =>{
// this.showPage();
//}
handleFileProgress(event){
let hero = document.getElementById('heroImage')
let loader = hero.getElementsByClassName('loader')[0];
}
loadImage(_img){
let el = document.getElementById('heroImage');
let loader = el.getElementsByClassName('loader')[0];
let loadManifest = [
{
id: 'pat',
src: _img,
scope: this
}];
this.preload.loadManifest(loadManifest, true);
}
showPage(){
//Helper.removeClass(document.getElementById('mytest','hidden'));
}
}
Ok, update after only 5 min....
Addded an arrow function as a variable and passed that on to the event listener. This is not my preferred way but it does work though...
constructor(){
let handleFileCompleted = (event) => {
this.showPage(event)
}
this.preload = new createjs.LoadQueue();
this.preload.addEventListener("fileprogress", this.handleFileProgress);
this.preload.addEventListener("fileload", handleFileCompleted);
}
showPage(event){
console.log('I'm now reachable!');
console.log(event); // fileload event
}
Perhaps this can help anybody out.
Still interested to see if there's a better way though...

Inheritance in Node.JS

I am using node.js and programming based on express.js. I have tried to use util.inherits to implement inheritance in JavaScript. What I've tried is as follows:
//request.js
function Request() {
this.target = 'old';
console.log('Request Target: ' + this.target);
}
Request.prototype.target = undefined;
Request.prototype.process = function(callback) {
if (this.target === 'new')
return true;
return false;
}
module.exports = Request;
//create.js
function Create() {
Create.super_.call(this);
this.target = 'new';
}
util.inherits(Create, Request);
Create.prototype.process = function(callback) {
if (Create.super_.prototype.process.call(this, callback)) {
return callback({ message: "Target is 'new'" });
} else {
return callback({ message: "Target is not 'new'" });
}
}
module.exports = Create;
//main.js
var create = new (require('./create'))();
create.process(function(msg) {
console.log(msg);
});
My scenario is :
I have Request as base class and Create as child class. Request has field target that initialize old in Request constructor.
Now, I create Create class object which first call Request constructor and then initialize target field with new. When I call process function of Create, I expect to get message of target is 'new' but it returns another!
I searched similar threads for this, but all are what i tried! Can any one explain what was wrong?
Thanks in advance :)
util.inherits has really awkward super_... anyway, this should work:
Create.super_.prototype.process.call(this, callback);
But really,
var super_ = Request.prototype;
And then the syntax becomes almost convenient:
super_.process.call(this, callback);

Resources