I have 2 files,
extendableError.js
class ExtendableError extends Error {
constructor(message) {
super(message)
this.name = this.constructor.name
this.message = message
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor)
} else {
this.stack = new Error(message).stack
}
}
}
module.exports = ExtendableError
duplicatedError.js
const ExtendableError = require('./ExtendableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
Below is my testing code,
const DuplicatedError = require('./duplicatedError');
const ExtendableError = require('./ExtendableError');
const ExtendableError1 = require('./extendableError');
try{
throw new DuplicatedError('hahah');
}catch(err){
console.log(err instanceof ExtendableError); // true
console.log(err instanceof ExtendableError1); // false
}
The test is on my mac book, why is that happen? Only the 1st charater was uppercase has different results. i don't understand.
Macs are based on BSD UNIX, so the file system is case sensitive.
As a side note, it’s common to not use camecase for file names, eg:
var extendableError = require(‘./extendable-error’)
Firstly, for compatibility reason, macOS chose a case-insensitive file system. But it doesn't mean you have to bear it, Disk Utility can be used to reformat the partition to case-sensitive mode. If You do that, node.js will report error to you because of the wrong module name you are trying to require.
Then, let's talk about your test result. The key issue is which one you require in duplicatedError.js, if you change it a little bit:
//change the required name to lowercase extendableError
const ExtendableError = require('./extendableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
The test result will be:
false
true
You can even try to modify duplicatedError.js like below:
//change the required name to extENDableError
const ExtendableError = require('./extENDableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
The result shall be
false
false
So i think it's not about module caching, you have two things to be clear here:
macOX is case-insensitive file system by default
even you have only one file extendableError.js, but you require twice with different names, like: require(./extendableError), require(./ExtendableError), require(./extENDableError), trey will be treated as three modules.
Related
I'm trying to make some code to insert node into generic config by xpath.
Usually I'm writing .Net applications but now I need to write tool on nodejs, type script
I don't get it how write it right
How to make cast of **childNodes[0]** so I can call **appendChild**?
import {DOMParser as dom} from "xmldom";
import * as xpath from "xpath";
export default class FileJob extends BaseJob {
async execute(settings: JobSettings) {
this.poke('C:\\Temp\\LocalCache\\Config.xml','/Root','<DB-Connection id="development" database="development"/>');
}
private poke(path:fs.PathLike,pathToNode:string, node : string)
{
const file = fs.readFileSync(path,'utf-8');
var doc = new dom().parseFromString(file);
var tempDoc = new dom().parseFromString(node);
var importedNode = doc.importNode(tempDoc.documentElement, true);
var childNodes = xpath.select(pathToNode, doc);
if (childNodes[0]!==undefined)
{
//What to do here?
//Property 'appendChild' does not exist on type 'SelectedValue'.
//Property 'appendChild' does not exist on type 'string'.
childNodes[0].appendChild(importedNode);
fs.writeFileSync(path,doc.toString());
}
}
}
I was stupid and young.
Here is what was necessary.
import {DOMParser as dom} from "xmldom";
import * as xpath from "xpath";
export default class FileJob extends BaseJob {
async execute(settings: JobSettings) {
this.poke('C:\\Temp\\LocalCache\\Config.xml','/Root','<DB-Connection id="development" database="development"/>');
}
private poke(path:fs.PathLike,pathToNode:string, node : string)
{
const file = fs.readFileSync(path,'utf-8');
var doc = new dom().parseFromString(file);
var tempDoc = new dom().parseFromString(node);
var importedNode = doc.importNode(tempDoc.documentElement, true);
var childNodes = xpath.select(pathToNode, doc);
if (childNodes[0]!==undefined)
{
let currentNode = childNodes[0] as Node;
currentNode.appendChild(importedNode);
fs.writeFileSync(path,doc.toString());
}
}
}
i'm little bit confused with my code below, i am trying to access the subscribers attribute of a Category class and get undefined:
class Category {
constuctor(name){
this.name = name; // Category name
this.subscribers = [];
}
subcribe(observer){
console.log(this.subcribers)
this.subscribers.push(observer)// <----------- this is undefined ????
}
sale(disoucnt){
this.subscribers.forEach(observer => observer.notify(this.name, discount))
}
}
module.exports = Category;
// Observer
class Shopper {
notify(name, discount){ console.log(name, discount) }
}
module.exports = Shopper;
Form main file
const Category = require('./Category')
const Shopper = require('./Shopper')
const book = new Category("Book");
const shopper = new Shopper("PAUL")
const subscribe = book.subscribe(shopper);
// Output : TypeError: Cannot read property 'push' of undefined
Why this.subscribers is undefined ? thanks for your help
Thanks guys
The code is riddled with typos: constructor not constuctor, subscribe not subcribe, subscribers not subcribers, discount not disoucnt.
Because of the constructor typo your class was not even getting instantiated.
class Category {
constructor(name){
this.name = name; // Category name
this.subscribers = [];
}
subscribe(observer){
console.log(this.subscribers)
this.subscribers.push(observer)
console.log(this.subscribers)
}
sale(discount){
this.subscribers.forEach(observer => observer.notify(this.name, discount))
}
}
// module.exports = Category;
// Observer
class Shopper {
notify(name, discount){ console.log(name, discount) }
}
// module.exports = Shopper;
const book = new Category("Book");
const shopper = new Shopper("PAUL")
const subscribe = book.subscribe(shopper);
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);
}
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.
The author of this article uses singletons for the service layer in this example Node api:
https://html5hive.org/how-to-create-rest-api-with-node-js-and-express/
He states, "We only want there to ever be one instance of our player service, so instead of exporting the class itself, we’ll export a new instance of it. Module files in node are only ever executed once, so this effectively gives us a singleton."
'use strict';
var uuid = require('node-uuid');
class PlayersService {
constructor() {
this.players = [];
}
getPlayers() {
return this.players;
}
getSinglePlayer(playerId) {
var player = this.players.filter(p => p.id === playerId)[0];
return player || null;
}
addPlayer(info) {
// prevent a bit of bad/duplicate data
if (!info || this.players.filter(p => (p.firstName === info.firstName && p.lastName === info.lastName)).length > 0) {
return false;
}
info.id = uuid.v4();
this.players.push(info);
return true;
}
updatePlayer(playerId, info) {
var player = this.getSinglePlayer(playerId);
if (player) {
player.firstName = info.firstName ? info.firstName : player.firstName;
player.lastName = info.lastName ? info.lastName : player.lastName;
player.displayName = info.displayName ? info.displayName : player.displayName;
return true;
}
return false;
}
}
module.exports = new PlayersService();
Which seems reasonable since the function of these services is to provide the same implementation for the controllers that use them.
However, in this post:
On Design Patterns: When to use the Singleton?
the poster asks for a legitimate use case for singletons other than a Logger class. Several people responded to his question by saying that singletons should never be used.
But isn't the use of singletons for services like the one I've copied here a legitimate use case and a best practice so that you are not creating multiple instances that provide the same implementation? Thanks.