Should I pass an objects as a parameters of a function? - javascript

So I have this code:
const failure1 = false;
const failure2 = false;
function callbackFunction(callback, errorCallback) {
if (failure1) {
errorCallback({
name: 'Negative event1 occurred',
message: ':('
})
} else if (failure2) {
errorCallback({
name: 'Negative event2 occurred',
message: ':/'
})
} else {
callback('Mission complete!')
}
}
callbackFunction((message) => {
console.log('Success: ' + message)
}, (error) => {
console.log(error.name + ' ' + error.message)
})
And that looks absolutely awful:
errorCallback({
name: 'Negative event2 occurred',
message: ':/'
})
Is it even ethical to pass an object as a function parameter like that? Because right now, my brain is frying only from looking at it.
How should I read it? Is that an unnamed object (assigned to the errorCallback function - that is a parameter of callbackFunction) with two properties (name and message) that is later assigned to an error parameter of an unnamed function (bottom of code)? Is that correct?
I also heard that this is a really easy piece of code - is that true? Because for me that's super convoluted.
Thank you in advance, for the time spent on an answer.

Passing Object as parameter sometimes actually makes more sense and more easy to read.
Example of a very simple function:
function minus(b,a){
return b-a
}
Usually people will use it as:
minus(1,5)
// Expected : 4, Because the latter number minus the first.
// But, it will return result of -4, without look into the function
// we do not know which number came first.
But if we make it an object:
function minus(param){
return param.b-param.a
}
minus({a:1,b:5})
//Return : 4
//Like this, even if you don't know the content of the function
//you can still assign the correct value without knowing the order.

Related

How to resolve no-param-reassign error in a function

In a Node/JS function, I'm getting ESLint no-param-reassign the code is for update a candidate as follow
update(candidate) {
const { id } = candidate;
if (!id) {
throw new UserInputError('id is mandatory');
}
return this.tx(tableName)
.returning(Object.values(columnsByProperties))
.where('id', id)
.update(prepareCandidate(candidate))
.reduce((_, b) => camelcaseKeys(b), null)
.then(x => {
if (!x) {
throw new UserInputError(`Candidate "id" with ${id} is not found`);
}
x.preferredContact = x.preferredContactHours;
return x;
});
}
The error specifically is here Assignment to property of function parameter 'x'
.then(x => {
if (!x) {
throw new UserInputError(`Candidate "id" with ${id} is not found`);
}
x.preferredContact = x.preferredContactHours;
return x;
});
You can replace:
x.preferredContact = x.preferredContactHours;
return x;
With this:
return { ...x, preferredContact: x.preferredContactHours };
This way you return a new object instead of modifying the function's parameter.
Now, elaborating a bit. As the rule's documentation says:
Assignment to variables declared as function parameters can be misleading and lead to confusing behavior, as modifying function parameters will also mutate the arguments object.
"Confusing behavior" is to be understood as, for example, odd side effects. I remember wreaking havoc in an app because inside a function, I mutated an array that was passed as a parameter. The array was also mutated in the calling code which was bad. That's the kind of thing ESLint helps prevent!

Cannot read property of undefined in class

I'm new to javascript so can anyone help me figure out why this code is not working?
I have a class and it calls a cordova barcode scanning function. I've got an example that works, however I want to be able to separate out the function(result) and function(error) and use onSuccess(result) and onFailure(error).
I have no idea why this is happening so if anyone can help that would be great.
EDIT: so ive updated the code based on Stradosphere said however im still getting result is not defined errors.
Full error message:
Uncaught ReferenceError: result is not defined at barcodeScanner.scanBarcode (barcodeScanner.js:10) at HTMLButtonElement.myFunction (main.js:18)
var me = this;
class barcodeScanner {
constructor() {
this._barcodeResult = 0;
}
scanBarcode() {
//THIS THROWS result is not defined error
cordova.plugins.barcodeScanner.scan(me.onSuccess(result), me.onFailure(error));
//THIS WORKS
cordova.plugins.barcodeScanner.scan(
function (result) {
me._barcodeResult = result.text;
alert("Barcode Scanned:" + me._barcodeResult);
},
function (error) {
alert("Scanning failed: " + error);
}
);
}
onSuccess(result) {
this._barcodeResult = result.text;
alert("Barcode Scanned:" + this._barcodeResult);
}
onFailure(error) {
alert("Scanning failed: " + error);
}
}
Looking at the docs, it appears that cordova.plugins.barcodeScanner.scan() expects you to pass a function into it. But you are calling it like this:
cordova.plugins.barcodeScanner.scan(me.onSuccess(result), me.onFailure(error));
This is passing the result of the function .onSuccess(result), but result is not defined, so you are getting an error. Additionally, you want this to be the class instance, but by defining me as this outside the class, me won't equal the class instance like you want it to. But you don't need it anyway.
Try passing functions in instead:
cordova.plugins.barcodeScanner.scan((result) => this.onSuccess(result),(error)=> this.onFailure(error))
Maybe a scope issue on your use of this. Try:
var me = this; //(put this at class level)
cordova.plugins.barcodeScanner.scan(me.onSuccess, me.onFailure);

ES6 Proxies: trapping undefined function executions

Let's say I have the following object with two functions as properties:
const foo = {
f1: () => {...},
f2: () => {...},
}
I would like to perform a specific action (for example, throw a custom error) when someone tries to execute a function that doesn't exist on the foo object.
I've tried using a get proxy, but that throws an error even when I'm not trying to execute f3, such as in the following code:
if (foo.f3) {...}
So how can I write my proxy in such a way that foo.f3 returns undefined as it usually would, but foo.f3() does throw an error?
Here's a partial solution, inspired by Unmiss.
const handler = {
get: function(obj, prop) {
if (prop in obj) {
return obj[prop];
} else {
return () => {
throw new Error(`Foo.${prop} is undefined`);
}
}
}
};
The problem with this is that while it accomplishes the goal of only throwing an error when you actually try to execute Foo.f3(), since Foo.f3 is now equal to that anonymous function is doesn't return undefined anymore, meaning that (as far as I can tell) if (Foo.f3) {...} will always return true.
Edit: as #paulpro points out:
You absolutely cannot do that. foo.f3 is either undefined or some
callable with custom logic; it cannot be both.
The best we could do is trap f3 in foo statements using the has trap, but this would mean if (f3 in foo) and if (foo.f3) would now have different results, which seems like a big red flag.
Is this what your asking for?
https://jsfiddle.net/MasterJames/bhesz1p7/23/
[obviously you need to F12 your dev tools to see the console output or change as desired]
Only real difference is to return undefined after throwing. It's as if the function executed without doing anything since it doesn't exist.
I'm sure there's a different solution based on the actual use case, but I like the idea/question. Keeps things more stable etc.
let foo = new Proxy(
{
f1: function (val) {
console.log(' F1 value:' + val);
return 'called OKAY with', val;
}
},
{
get: function(obj, prop) {
console.log("obj:", obj, " prop:", prop);
if (prop in obj) {
console.log("Found:", prop);
return obj[prop];
}
else {
console.log("Did NOT find:", prop);
throw new Error(`Foo.${prop} is undefined not called returning undefined`);
return undefined;
}
}
});
console.log("\nFoo Tester started");
console.log(' Does F1 exists', foo.f1 !== undefined);
console.log(' called F1 result:', foo.f1('passed') );
try {
console.log(' Does F2 exists', foo.f2 !== undefined);
console.log(' called F2 result:', foo.f2('passed') );
}
catch (err) {
console.log(' Error calling F2:', err );
}
console.log("Foo Tester finished");
Not sure you want to try-catch or not that's also up to you so in the end checking if it's real and a function is the same difference depending on how your going to handle the error.
if (foo.f2 && foo.f2.constructor === Function && foo.f2()) console.log("okay!");
Again you call build a safeCall wrapper more like this or something in between?
possible calling foo's 'customThrow' if it exists or what-have-you, so many possibilities with JS.
Okay so it took me sometime but I have a solution now.
I was not fully understanding your question, which I reformulated as a question within the question for myself to understand the issue better as it is complicated.
Basically you want to know if it's being called or not so the function you need in the proxies 'get' is 'isCalling'.
The solution is not clean in JS Fiddle because it's messy there at least for this kind of problem's solution.
Basically the solution is a sentence is, "you have to use an error to get a stack trace then retrace the source code that is calling and look for a right bracket or not.", to determine how it's being called and return whatever you want then).
[Please note this depends on your code and how you call it so you would adjust as needed.]
Since you have to find the location in the source code that's being called from it's way better if there is no inline script tag as is the case in this JSFiddle example. I'm using outerHTML to get the source, when arguments.callee.caller.toString() is better from an actual JS file. You'll also not the location from the stacktrace is skewed by odd behavior here, so with a normal JS file the code would align properly using other solutions are recommended. If anyone knows how to get a clean source that aligns with the error trace every time with script-tag blocks etc. Also note coming but not existing yet are things like Error.lineNumber.
[Please don't bother with the version history it was a nightmare to sort this one out. And again you would be better to use other npm packages to do the source code from stack trace parts.]
Anyway the example I believe achieves what you want but in principle demonstrates what you'd need to do better in a given real (no Fiddle) situation. I'm pretty sure doing this is not a great solution in production either and I've not tested the timing (performance speed) but if it really was that important to your cause (and no other better solution which I doubt) then it will work.
Originally I discovered this technique when I was doing something experimental, and instead of just sending another argument I was checking to see what was actually calling it and adjusting the functions action depending.
Usages are extensive when you start to think more about it as I did last year when I first did something like this. Examples are as an extra function execution Security Check, Realtime mystery-bug Debug Solution, a way to execute the function differently without passing more arguments, runaway recursive loops (how long is the stack), to name a few.
https://jsfiddle.net/MasterJames/bhesz1p7/90/
let foo = new Proxy(
{
f1: function (val) {
console.log(' F1 value:' + val);
return 'called OKAY with', val;
}
},
{
isCalling: function() {
let stk = new Error();
let sFrms = this.stkFrms(stk.stack);
console.log("stkFrms:", sFrms);
//BETTER From real pure JS Source
//let srcCod = arguments.callee.caller.toString()
let srcCod = document.getElementsByTagName('html')[0].outerHTML.split("\n");
let cItm = sFrms[(sFrms.length - 1)];
if(cItm !== undefined) {
let cRow = (parseInt(cItm[1]) - 3);
let cCol = (parseInt(cItm[2]) + 1);
let cLine = srcCod[cRow];
let cCod = cLine.substr(cCol, 1);
if(cCod === '(') return true;
}
return false;
},
stkFrms: function (stk) {
let frmRegex1 = /^.*at.*\(.*\:([0-9]*)\:([0-9]*)\)$/;
let frmRegex2 = new RegExp(frmRegex1.source, 'gm');
let res = [], prc, mtch, frms = stk.match(frmRegex2);
for(mtch of frms) {
prc = frmRegex1.exec(mtch);
res.push(prc);
}
return res;
},
get: function(obj, prop) {
if (prop in obj) {
console.log("Found:", prop);
return obj[prop];
}
else {
if(this.isCalling() === false) {
console.log("Did NOT find:", prop);
return undefined;
}
else {
console.log("Did NOT find return custom throw function:", prop);
return function() {throw new Error(`Foo.${prop} is undefined`);}
}
}
}
});
console.log("foo.f1:", foo.f1);
console.log("foo.f1('passed'):", foo.f1('passed'));
console.log("foo.f2:", foo.f2);
try {
console.log("foo.f2('passed2'):", foo.f2('passed2'));
}
catch(err) {
console.log("foo.f2('passed2') FAILED:", err);
}
console.log("'f2' in foo:", 'f2' in foo);
Okay so a verbal run through:
You want to check foo.f2 is undefined so it returns that because it's not being called.
If you do call it (f2) without simply checking first and erroring as needed, and you don't want to try-catch to throw your custom error based on the function name, you want it to return an actual function that will throw a custom error.
You also want to use 'in' to see that it's undefined, which is the same as false (maybe hack it further to send false instead of undefined via something like isCallingFromIn too.
Did I miss anything? Is this not what you all thought was impossible?

React Native function calls not working – can’t find `this.function2`

I cannot get this working. It might be simple but there is just no information online that works.
Here is what I am trying to do.
class Test {
componentDidMount() {
this.function1();
}
function1() {
var myListener = listener.on(something) {
console.log('function1 triggered');
key = 'djh3489739082';
name = 'gary';
email = 'gary#email.com';
this.function2(key, name, email);
}
}
function2 = ({ key, name, email }) => {
console.log('key: ' + key);
console.log('name: ' + name);
console.log('email: ' + email);
}
}
That's basically it. The error I get in the console is that it can't find variable this.function2.
It doesn't work when I try removing the this. prefix. I also have a much simpler function call in my code that works fine like this:
function3() {
// Some code here
this.function4();
}
function4() {
// Do some things.
}
And function3 calls function4 without issue. It's just because I need to pass parameters that it falls over and like NO ONE online needs to do this, apparently. The only examples I have found use const before the function. So like:
const function2 = ({ parameter1, parameter2, parameter3 }) => {
But this immediately throws an error. I can't use const or var or any of that stuff.
This should be easy, surely! Any ideas?
Here's what's wrong in your code. How many parameters does your function2 take? One, not three, but one. It takes a JSON object as a parameter, who has 3 properties: key, name and email, because you wrapped them with {}, but when you call it in function1, you passed 3 parameters to it, without the {}, which makes it not a JSON object.
So, you can either:
// Don't modify function2 but change function1 like so
function1() {
this.function2({ key, name, email })
}
or
// Don't modify function1 but change function2 like so
function2(key, name, email) {
}

How to pass a parameter to a function that is passed to another function as string?

I have the following piece of code :
accountSelector.executeInParallel('processAccounts', 'postProcess');
function processAccounts() {
return JSON.stringify(syncMasterLists());
}
And instead of having this, I want to be able to pass a value to the processAccounts accounts function.
For the purpose I changed the code so it's looking like this now :
accountSelector.executeInParallel('processAccounts("DE")', 'postProcess');
function processAccounts(arg) {
return JSON.stringify(syncMasterLists());
}
Unfortunately, after introducing the change I started getting the following error :
Cannot find function processAccounts("DE").
I cannot understand am I doing this wrong(and if yes then what is wrong) or it's just something that can't be done.
I cannot understand am I doing this wrong(and if yes then what is
wrong) or it's just something that can't be done.
accountSelector.executeInParallel takes the function name as parameter and execute the same, processAccounts("DE") is not a valid function name or the name of the function that exists.
As per documentation, there is a way to pass optionalInput parameter
The input, if specified by optionalInput, will be passed into the
function specified by functionName
accountSelector.executeInParallel(functionName, optionalCallbackFunctionName, optionalInput)
In your case, it will be
accountSelector.executeInParallel('processAccounts', 'postProcess', 'DE' );
Why don't you call the function first and replace the result in the 'executeInParallel' method as follows:
var res = processAccounts("DE");
accountSelector.executeInParallel(res, 'postProcess');
function processAccounts(arg) {
return JSON.stringify(syncMasterLists());
}
Some closure can probably solve your problem, depends on how accountSelector.executeInParallel is implemented
const accountSelector = {
executeInParallel(pre, post) {
let result = eval(pre)()
eval(post)(result)
}
}
accountSelector.executeInParallel(processAccountsWithArg('Foo'), 'postProcess');
function processAccount(arg) {
console.log('processAccount', arg)
return JSON.stringify({
key: 'value'
});
}
function processAccountsWithArg(arg) {
return function() {
return processAccount(arg)
}
}
function postProcess(result) {
console.log('postProcess', result)
}

Categories