how to export Reflect.defineProperty()? - javascript

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);
}
// ...

Related

Why won't a boolean object property update?

I have an array of objects. Each object has a method that should update a boolean property in the same object called 'found'.
When I call the function, the property does not update. I am not sure why.
I thought that the 'found' property would be accessible but it isn't??
I have created a minimal version of the problem here:
https://codepen.io/sspboyd/pen/XWYKMrv?editors=0011
const gen_s = function () { // generate and return the object
let found = false;
const change_found = function () {
found = true;
};
const update = function () {
change_found();
};
return {
change_found,
found,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].found); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].found);
When your change_found function changes the value of found, it's changing the value pointed to by your let found variable, but the object returned by your gen_s function still points to the old value.
You can fix your code using the 'holder' pattern, like this:
const gen_s = function () { // generate and return the object
let foundHolder = {value: false};
const change_found = function () {
foundHolder.value = true;
};
const update = function () {
change_found();
};
return {
change_found,
foundHolder,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].foundHolder.value); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].foundHolder.value);
Or even better, use a class:
class S {
constructor() { this.found = false; }
change_found() { this.found = true; }
update() { this.change_found(); }
}
const s_arr = [];
s_arr.push(new S());
console.log(s_arr[0].found);
s_arr.forEach(s => s.update());
console.log(s_arr[0].found);

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.

String with a variable that can be replaced (php's sprintf equivalent)

I have a class that looks like below
interface IParams: {
academicYearId: number;
// Other Params
};
export class myClass() {
function1() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 1 Functionality
}
function2() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 2 Functionality
}
function3() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 2 Functionality
}
}
To reduce on the repetition I made url a property
interface IParams: {
academicYearId: number;
// Other Params
};
export class myClass({academicYearId}: ) {
url = `api/accounts/academic-year/:id/financial-plan`;
urlWithId = (academicYearId: number) => this.url.replace(':id', academicYearId )
function1() {
const url = this.urlWithId(academicYearId)
// Function 1 Functionality
}
function2() {
const url = this.urlWithId(academicYearId)
// Function 2 Functionality
}
function3() {
const url = this.urlWithId(academicYearId)
// Function 2 Functionality
}
}
The above approach works but am I was wondering if there is a better way I can approach the below two lines other than setting a part of the string to ':id' and then replace that part with the id value. Something like in php's sprintf
url = `api/accounts/academic-year/:id/financial-plan`;
urlWithId = (academicYearId: number) => this.url.replace(':id', academicYearId )
String interpolation
It's a common approach for doing that like below:
urlWithId = (academicYearId) => `api/accounts/academic-year/${academicYearId}/financial-plan`;

How to self-reference NodeJS Module?

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)
}
}

How to prevent the T function from being wrapped in the anonymous function using babel?

I have the following javascript file to be parsed with babel:
b(a)
I have the following javascript file that I use to detect calls to functions in the previous file and replace them with a function that receives the previous function and its parameters to call it.
const t = require("babel-types")
module.exports = function (babel) {
return {
visitor: WrapperVisitor
}
}
const WrapperVisitor = {
Program(path) {
path.traverse(CallVisitor)
}
}
let cont = 0
const CallVisitor = {
CallExpression(path) {
if (path.node.callee.name){
let cam = path.node.arguments.slice()
path.node.arguments.push(t.identifier(path.node.callee.name))
path.replaceWith(
t.functionDeclaration(
t.identifier("T"),
path.node.arguments,
t.blockStatement(
[
t.expressionStatement(
t.callExpression(
t.memberExpression(
t.identifier(path.node.callee.name),
t.identifier("apply")
),
cam
)
)
]
)
)
)
}
}
}
This generates the following output file
(function () {
function T(a, b) {
return b.apply(a);
}
})();
The question is: how to prevent the function T from being wrapped in the anonymous function and in those parentheses, and where can I find more documentation of the path object?

Categories