How to self-reference NodeJS Module? - javascript

I have a module that I'm exporting. I need one function to call another function. Here's a simplified version of what I'm trying to do.
module.exports = {
isEven: (number) => {
return (number%2 == 0)
},
isTenEven: () => {
return isEven(10)
}
}
The code above throws isEven is not defined when moduleName.isTenEven() is called.
It makes sense why it fails. But how would you rewrite it? (While maintaining the singleton pattern)

Define the functions first, then export them:
const isEven = (number) => number % 2 === 0
const isTenEven = () => isEven(10)
module.exports = {
isEven,
isTenEven
}

The object is only used to group the functions together. There's nothing really OO about it so define the functions separately. Construct the object at the end.
const isEven = number => number % 2 === 0;
const isTenEven = () => isEven(10);
module.exports = { isEven, isTenEven };

Maybe just do this? Define then export.
const isEven = number => number % 2 === 0;
module.exports = {
isEven,
isTenEven: () => isEven(10)
};

Just to add one more solution to the mix. You don't have to define the function elsewhere. Since the object declaration is complete before the function gets called, you can refer to it via module.exports or via exports like this:
module.exports = exports = {
isEven: (number) => {
return (number%2 === 0)
},
isTenEven: () => {
return exports.isEven(10)
}
}
If you were doing this in a lot of methods, you could define a shorter variable name for the exported object and refer to it.

If you can afford Babel or a version of Node.js that supports import/export statements you could also do:
export const isEven = num => num % 2 === 0;
export const isTenEven = () => isEven(10);

Inside JS object literal using this refers to the object itself so you can have:
module.exports = {
isEven: (number) => {
return (number%2 == 0)
},
isTenEven: function () {
return this.isEven(10)
}
}

Related

Dynamic Function Watcher in JS

I'm working on a pet project, a little front-end library for students. It reads variables/code in a JS file and tests it, outputting some panels. The code itself roughly follows the Jest framework.
My problem is that I'm trying to create a function that watches the execution of other functions, counts them, and lets me access the count.
function watchFunction(funcName){
let originalFunction = window[funcName];
let counter = 0;
// Wrap the function, counts when called
window[funcName] = function(...args){
console.log("watching");
counter++;
return originalFunction(...args);
}
return {
getCount: () => {return counter},
reset: () => {
// Unwrap the function
window[funcName] = originalFunction
}
}
}
This seems to work for methods like Number() or parseInt(), but I don't know how I would go about accessing methods like Math.floor(), or prototype methods like Array.prototype.map().
I've tried passing in the function reference instead of using window["funcNameString"], but that doesn't seem to work.
Does anyone have suggestions or tips for wrapping functions or watching functions like this?
EDIT:
It appears a solution was found!
function watchFunction(obj, fName) {
let counter = 0;
const originalFunction = obj[fName];
obj[fName] = (...args) => {
counter++;
return originalFunction.bind(obj)(...args);
};
return {
removeWatcher: () => (obj[fName] = originalFunction),
resetCount: () => (counter = 0),
getCount: () => counter,
};
}
Example of use:
// Array.prototype.push
const arrayPushWatcher = watchFunction(Array.prototype, "push");
let arr = [];
// 0
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arr.push(1);
// 1
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arr.push(1);
// 2
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arrayPushWatcher.removeWatcher();
arr.push(1);
// 2 (stopped counting)
console.log("Array.prototype.push", arrayPushWatcher.getCount());
How to watch for any function call
Is that what you want? I can also write a block for this function so that it determines whether an object has been passed in or a string. If string -> run this function on window as a property "objectThatStoresFunction".
I've tried playing around with the Function.prototype, but it doesn't really work. So the function turned out a bit more complex.
This code below works both with functions / objects on window Array.prototype.map (Prototype / Class functions)
function watchFunction(objectThatStoresFunction, functionName) {
let counter = 0;
const originalFunction = objectThatStoresFunction[functionName];
objectThatStoresFunction[functionName] = (...args) => {
counter += 1;
return originalFunction(...args);
}
return {
getCount: () => {
return counter
}
}
}
const mathRoundWatcher = watchFunction(Math, 'round');
// 0
console.log(mathRoundWatcher.getCount());
// 1
Math.round(99666.9999999);
console.log(mathRoundWatcher.getCount());
// 2
Math.round(999999999.99);
console.log(mathRoundWatcher.getCount());
function watchFunction(objectThatStoresFunction, functionName, optionalOriginalFunction) {
const self = this;
if (optionalOriginalFunction) {
objectThatStoresFunction = this.window;
functionName = optionalOriginalFunction.name;
}
let counter = 0;
const originalFunction = objectThatStoresFunction[functionName] || optionalOriginalFunction;
objectThatStoresFunction[functionName] = (...args) => {
counter += 1;
return originalFunction.bind(self)(...args);
}
return {
// should it remove the watcher or reset the count?
reset: () => objectThatStoresFunction[functionName] = originalFunction,
getCount: () => {
return counter;
}
}
}
const arrayMapWatcher = watchFunction(Array.prototype, 'map');
// 0
console.log('Array.prototype.map', arrayMapWatcher.getCount());
[-99].map(() => {});
// 1
console.log('Array.prototype.map', arrayMapWatcher.getCount());
const mathRoundWatcher = watchFunction(Math, 'round');
// 0
console.log('Math.round', mathRoundWatcher.getCount());
// 1
Math.round(99666.9999999);
console.log('Math.round', mathRoundWatcher.getCount());
// 2
Math.round(999999999.99);
console.log('Math.round', mathRoundWatcher.getCount());
const alertWatcher = watchFunction(null, null, window.alert);
// 0
console.log('window.alert', alertWatcher.getCount());
// 1
window.alert('1');
console.log('window.alert', alertWatcher.getCount());
// 2
alert('2')
console.log('window.alert', alertWatcher.getCount());
// reset the alertWatcher counter
alertWatcher.reset();
This code above breaks the stacksnippets.com when used with Array.prototype.map for some reason, please see this JsFiddle link:
https://jsfiddle.net/ctbjnawz/3/
Do you mean a method of an instance or object? One way is to create a new function. e.g
function WatchInstanceMethods(instance, functionName){
let originalFunction = window[instance][funcName];
let counter = 0;
window[instance][functionName] = function(...args){
console.log("watching");
counter++;
return originalFunction(...args);
}
return {
getCount: () => {return counter},
reset: () => {
// Unwrap the function
window[funcName] = originalFunction
}
}
}
although adding support for chaining methods will get difficult with more nested methods but you can pass a string for functionName name and split it to have each layer of calling instance for function and repeat the logic above.

if can't access parameter in JavaScript module

Hi I'm having problems with the scope of an if in a JavaScript module.
Here is a mock up of my code :
module.exports = {
caser(nb){
if(0 === 0){
nb = 3+2
}
}
}
The function is called from another JavaScript file. Nb however doesn't change when I do this.
My editor (visual studio code) marked nb as unused. This I tried :
module.exports = {
caser(nb){
let number = nb
if(0 === 0){
number = 3+2
}
}
}
This still doesn't seem to alter the value of nb. Does anyone know a solution to this problem?
Thanks in advance.
Reassigning nb (or number) will only change what those variable names point to in the current function. It sounds like what you need to do is return the changed value, and have the consumer of the function use it to reassign the value it passes in. Something like:
// consumer file:
const { caser } = require('./foo');
let nb = 5;
nb = caser(nb);
module.exports = {
caser(nb) {
if (0 === 0) {
nb = 3 + 2
}
return nb;
}
}
The only way to avoid having to reassign in the consumer would be for the consumer to pass an object instead, and mutate the object.
// consumer file:
const { caser } = require('./foo');
const objToPass = { nb: 5 };
caser(objToPass);
module.exports = {
caser(objToPass) {
if (0 === 0) {
objToPass.nb = 3 + 2
}
}
}

how to export Reflect.defineProperty()?

So I've been using a bunch of these in my main javascript initiation file, there's like 20-30 of these that I need. Is there a way that I can export these from a different files so I can clear up my main file?
Reflect.defineProperty(numerator, 'getBalance', {
value: function getBalance(id) {
const TEMPLATEUser = numerator.get(id);
return TEMPLATEUser ? TEMPLATEUser.balance : 0;
},
});
I think you can create a function to abstract away what you're doing. Suppose you define this function in a file called file1.js and you want to use it in file2.js.
// file1.js
module.exports.defineGetBalance = obj => {
Reflect.defineProperty(obj, 'getBalance', {
value: function getBalance(id) {
const TEMPLATEUser = obj.get(id);
return TEMPLATEUser ? TEMPLATEUser.balance : 0;
},
});
};
Now you can call defineGetBalance() as many times as you can, you just have to pass the object you want to assign that getBalance function into.
// file2.js
const { defineGetBalance } = require('./file1');
// ...
defineGetBlance(obj1);
defineGetBlance(obj2);
// now both obj1 and obj2 have a getBalance() function
const balance1 = obj1.getBalance(id1)
const balance2 = obj2.getBalance(id2)
// you a for loop if you can
for (const obj of arrObj) {
defineGetBalance(obj);
}
// ...

attempt to compress inside of (simple) function into more efficient code

I wrote a simple function that adds and removes classes for elements (buttons).
function mainBut (){
ba.classList.add("act2");
ba.classList.remove("hov")
bh1.classList.add("hov");
bh1.classList.remove("act2");
bh2.classList.add("hov");
bh2.classList.remove("act2");
da.classList.remove("none")
dh1.classList.add("none")
dh2.classList.add("none")
}
But as the number of elements grows, i see that the code could be better organized. Because we could:
remove: .act2 for (bh1 and bh2) | add: .hov for (bh1 and bh2) | add: .none for (dh1 and dh2).
I'm wondering, if it could be done using for loop? Or maybe there is a better way...
You can use functional programming to simplify it. Break-in small function and reuse.
const add = cls => elm => elm.classList.add(cls);
const remove = cls => elm => elm.classList.remove(cls);
const addAct2 = add("act2");
const addHov = add("hov");
const removeAct2 = remove("act2");
const removeHov = add("hov");
const addNone = add("none");
const removeNone = add("none");
function mainBut() {
addAct2(ba);
removeHov(ba);
addHov(bh1);
removeAct2(bh1);
addHov(bh2);
removeAct2(bh2);
removeNone(da);
addNone(dh1);
addNone(dh2);
}
// MORE FUNTIONAL
const curry = (fn, arity = fn.length, ...args) =>
arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
const apply = curry((fn, data =[]) => data.map(fn))
function mainBut() {
apply(removeHov, apply(addAct2, [ba]))
apply(removeAct2, apply(addHov, [bh1, bh2]))
apply(removeNone, [da])
apply(addNone, [da, dh1, dh2])
}

module.exports multiple functions in Jest testing

After reading the Jest documentation, when it's mentioned that to export a single function from a tested file they show the following example:
function sum(a, b) {
return a + b;
}
module.exports = sum;
Now, if I have multiple specific functions I want to export on my tested file, like this:
function sum(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function subtract(a, b) {
return a - b;
}
module.exports = sum;
module.exports = multiply;
The multiply function is the only one being exported. How can I make these function be exported? Or only part of my file?
You can do something like this :
module.exports = {};
module.exports.sum = function sum(a, b) {
return a + b;
}
module.exports.multiply = function multiply(a, b) {
return a * b;
}
module.exports.subtract = function subtract(a, b) {
return a - b;
}
End you use it like this:
var MyMathModule = require('./my_math_module');
MyMathModule.sum(a, b);
MyMathModule.multiply(a, b);
MyMathModule.subtract(a, b);
First, in your example, all you are doing there is overriding the exports object with a function ( which is totally fine )
The exports and module.exports are an object and are actually the same object ( i.e. module.exports === exports // true )
To do what you want you can do this a couple ways:
exports.sum = sum
exports.multiply = multiply
or
module.exports = { sum: sum, multiply: multiply } // etc
or
module.exports.sum = sum
module.exports.multiply = multiply
Having in mind the answer to this question, i'll paste here 2 ways to do the same thing.
For example, you have the JS file called exercise5, like this:
//You can create an object with functions, as follows:
const wordAnalysis = {
type: (word) => typeof (word),
whiteSpaces: (word) => {
let wordAnalysis = word.includes(' ')
if (wordAnalysis) {
return 'It has spaces'
} else {
return "It doesn't has spaces"
}
}
}
//Or you can create several single functions, like the following:
function numberAnalysis(word) {
let isANumber = typeof (word) === 'number' ? true : false
return isANumber
}
// în order to avoid overwriting the module.exports, it is needed to do one of the following (I chose the first one):
// 1)
module.exports.firstPlace = wordAnalysis
module.exports.secondPlace = numberAnalysis
// 2)
// module.exports = {
// functions: functions,
// isANumber: isANumber
// }
// 3)
// exports.functions = functions
// exports.isANumber = isANumber
// 4)
// exports = {
// functions: functions,
// isANumber: isANumber
// }
Now the file test named exercise5.test.js:
const wordAnalysis = require('./exercise5')
const numberAnalysis = require('./exercise5')
test('It should give me the type of what was typed', () => {
expect(wordAnalysis.firstPlace.type('teste')).toEqual('string')
})
test('It should give me the type of what was typed', () => {
expect(wordAnalysis.firstPlace.type(22)).toEqual('number')
})
test("It should give true if what is typed has at least a space or false if it doesn't", () => {
expect(wordAnalysis.firstPlace.whiteSpaces('Jon is cool')).toEqual('It has spaces');
})
test("It should give true if what is typed has at least a space or false if it doesn't", () => {
expect(wordAnalysis.firstPlace.whiteSpaces('AllTogetherNow')).toBe("It doesn't has spaces");
})
test('it should analyse if the given expression is a number or not', () => {
expect(numberAnalysis.secondPlace(2)).toBeTruthy()
})
test('it should analyse if the given expression is a number or not', () => {
expect(numberAnalysis.secondPlace('jon')).toBeFalsy()
})
The only thing you need to be aware is to export/import the correct object/function, and of course call it when your are developing the test.

Categories