How to optimize a parameter validation in Javascript - javascript

I have one very interesting question.
We know that we should check every parameter in a function.
So we want to check : if param exists, if type is correct, if it is contain some property in case of JSON type etc. and it should be done in every function.
actually how we can optimize and and avoid a tons of conditional if-else?
I tried to do something like that, but I don't know if it's good. Because it just throws an error and stops a program. But I don't know how it can be done better. I thought that es7 decorators will help me but it isn't because I can't use it for the properties checking because it works only with classes and methods.
export function isExists(param) {
if (param) {
return true;
}
throw new TypeError("Param should exists. Please check it.");
}
export function isJsonObject(itemToTest) {
if (itemToTest) {
return ~Object.prototype.toString.call(itemToTest).search(/Object/);
}
throw new TypeError("itemToTest should exists if you want to test it. Please check it.");
}
export function isOwnPropertyExist(objToTest, propName) {
isExists(objToTest); // Here i want to continue a program workflow or it will be broken if my checking won't have success
isExists(prop);
isJsonObject(objToTest);
if (objToTest.hasOwnProperty(propName)) {
return true;
}
throw new TypeError("objToTest should exists and contains a property with name ");
}
Thanks for any help! This question is tormenting me a more than 2 years.
P.S. I don't want to use Typescript (I just want to know, how do you resolve this moment)

Related

JavaScript/NodeJs Exception Handling

I'm confused how to properly catch JavaScript exceptions. I have a background as a Java Dev, so much of what I know about error handling comes from it.
I'm using sequelize for persistence, so messing around with it, I found an example on the web:
try {
//do sequelize stuff
} catch (error){
switch (error.name) {
case 'SequelizeUniqueConstraintError':
//do something
break;
case 'SequelizeValidationError':
//do something else
break;
default:
//do panic stuff
}
}
Well... that encouraged me to take a look inside sequelizer's source code...
What is thrown, is basically that:
class UniqueConstraintError extends ValidationError {
constructor(options) {
options = options || {};
options.parent = options.parent || { sql: '' };
options.message = options.message || options.parent.message || 'Validation Error';
options.errors = options.errors || {};
super(options.message, options.errors);
this.name = 'SequelizeUniqueConstraintError';
this.errors = options.errors;
this.fields = options.fields;
this.parent = options.parent;
this.original = options.parent;
this.sql = options.parent.sql;
}
}
hmmm... Interesting.... why would an exception have a name, besides already having a type?
So I changed my code to deal with the types themselves instead of the names, and it ended up like this:
try {
//do sequelize stuff
} catch (error){
if (error instanceof UniqueConstraintError) {
//do something
} else if (error instanceof ValidationError) {
//do something else
} else {
//do panic stuff
}
}
Needless to say, both work just fine.
Is there something I'm missing here? Am I following the wrong tutorials?
Witch solution would be the 'par excellence' in order to deal with multiple possible exceptions being thrown in modern JavaScript?? (witch may be not necessarily any of the two I've presented here)
Thanks.
Why would an exception have a name, besides already having a type?
For the same reason as using error codes: they serialise well and don't require a reference to the class. Also in some rare occasions (that should be avoided) you might end up with multiple copies of the library being loaded, which define multiple distinct classes with the same name. Checking the .name string still works, using instanceof only works if you reference the same class.
Which solution would be the 'par excellence' in order to deal with multiple possible exceptions being thrown in modern JavaScript?
If instanceof works for you, there's nothing wrong with using it - it's perfectly idiomatic. It's just that some programmers prefer a more defensive style that's more resilient in the face of bugs. Using string constants has its own set of problems, e.g. being prone to misspelling and API incompatibility.
Checking the value of a name property may be considered safer and/or simpler because:
for example, an instance of UniqueConstraintError is also an instance of ValidationError because the former extends the latter, so the order of the instanceof checks is crucial, and easy to get wrong.
for example, instanceof UniqueConstraintError may return false if the instance originated from a different execution context with its own global scope, such as that of an iframe.
If you are happy that neither of these reasons is pertinent then instanceof is more idiomatic and the better choice in my opinion.

Can't access "this" from only one method

I'm just missing something (which is terrible considering the kind of thing I'm missing) about "this". I have a class for log formatting. In only one method, which is intended only for debugging/testing, "this" turns out to be undefined. I removed almost everything for demonstration purposes only. The code goes as following:
class LogFormatter {
constructor(source) {
// nothing relevant.
}
formatted() {
return 'returns a formatted string whatever';
}
clog(message, sub) {
console.log(this.formatted());
}
// made only for testing
showThis() {
console.log(this);
}
}
And it is used like this:
const
LogFormatter = require('log-formatter'),
lgf = new LogFormatter('asd');
lgf.clog('whatever');
If I access this from formatted method, or even by calling showThis, it works just fine. So it does not seems to be something related to console.log.
When I call clog method, the next error is thrown:
console.log(this.formatted());
^
TypeError: Cannot read property 'formatted' of undefined
So, only in clog method, "this" is undefined. So what's the elephant in front of my that I'm not seeing? :)
EDIT: Note that if I add a console.log(this) inside the formatted method, works fine too.
Also, I've noticed that if I -try to- create a new object from LogFormatter this way:
const
LogFormatter = new require('log-formatter')('whatever')
Throws an exception, saying that I cant execute LogFormatter without new keyword, which AFAIK, should work, given the fact that the class is the only thing being exported via module.exports = LogFormatter. Also, I did not have this problem using good old constructor functions syntax.
Thanks in advance :)

JasmineJS 'isNot' property

Real quick about jasmine.addMatchers. With the latest Jasmine build from git, it appears as though the format for doing custom matchers is vastly different than code I'm seeing in the 'Jasmine JavaScript Testing' book. In the book it has code such as:
this.actual or maybe even this.isNot
The new format is something like:
compare: function (actual, expected) {
return {
pass: some true or false statement...
}
}
So, in this case, the 'this.actual' is actually the passed in argument 'actual', which is cool. How about accessing the isNot property if we're calling a new matcher such as:
expect(investment).not.toBeAGoodInvestment();
So, inside the body of 'toBeAGoodInvestment', we should be able to access the 'isNot' property. Not sure how to do that with the new format. I figured out how to set the this.message from the old way to the new way as in:
return {
pass: some statement...,
message: 'some message'
}
The message we would want to have show up in the jasmine reporter would be dynamic based on whatever the 'isNot' is set to.
After digging around in the actual Jasmine.js source, I found out where the arguments were getting passed into custom matcher's compare function, and indeed, the 'isNot' was not making it's way in at all. The 'this.isNot' was available in the context of the 'Expectation.prototype.wrapCompare' function within the Jasmine source itself but where it was really needed was the custom matcher I created.
So now in this wrapCompare function, I simply added the args.push statement within the 'if' statement as in:
if (this.isNot) {
//-- Added this line
args.push(this.isNot);
matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
}
Now, calling the matcher, I can do this:
expect(investment).not.toBeAGoodInvestment();
And then the actual matcher it will look something like this:
toBeAGoodInvestment: function () {
return {
compare: function (actual, isNot) {
return {
pass: actual.isGood(),
message: 'Expected investment to be a ' +
((isNot) ? 'bad' : 'good') + ' investment'
}
}
};
}
Nice little research task here to figure out what Jasmine was doing behind the scenes.
Any other way to get the 'isNot' injected into the compare function, let me know.

PEG.js: how to use prompt?

I'm creating a C++ parser with PEG.js, and I need to be able to use cin. With the after-match JS, when I use prompt(), the (alternate) online version throws an error of 'Parse Error: prompt is not defined'. I am trying to use the initializer to create a function to replicate prompt (probably not optimized, I was just trying it as a solution). However, when I do this, it still gives me the error. I have tried using window.prompt as well, but again, it does not work. Here's an example of what I'm doing:
{
function cin() {
window.prompt("");
}
function changeVar(variable, newValue) {
if(typeof variable === typeof newValue) {
variable = newValue;
} else if(typeof variable === 'undefined') {
alert("You can't assign a value to a variable if the variable isn't declared yet!");
} else {
alert("Bad assignment. In C++, a variable *must* have the same type *all the time*.");
}
}
}
stdin =
whitespace* "std::cin" whitespace* ">>" whitespace* varToBeChanged:[a-zA-Z_]+ ";" whitespace*
{ changeVar(varToBeChanged, cin('')); return varToBeChanged; }
whitespace =
space:[ \t]
{ return space; }
and then in the parser testing field:
std::cin >> variable;
Thank you for looking. I have tried Googling this and SO-searching this but I haven't found any results.
Also, here is the main piece of code, for all the (current) extra information anyone needs. I am having some problems with this as well, but I'll try to figure them out on my own before I post another question.
If you are using http://peg.arcanis.fr/, then the parser code is executed inside of a Web Worker - which has no access to any UI like the window or the DOM. The error "undefined variable" means literally that there is no window or prompt declared.
If you paste your code into http://pegjs.majda.cz/online, it is executed in the web page environment and works flawlessly.

Why is this function considered to be a constructor by linters?

I've been rewriting various bits of code I've 'inherited' and come across something I don't understand. Both jslint and jshint think the below function is a constructor, and I have no idea why.
function GEReqsDone(failed) {
if (!failed) {
alert('Thank you for your submission! The page will now be reloaded.');
document.location.replace(mwConfig.wgScript + '?title=' + encodeURIComponent(mwConfig.wgPageName) + '&action=purge');
} else {
alert('An error occurred while submitting the edit.');
button.disabled = false;
button.innerHTML = 'Update price';
}
}
This is a callback from query using $.ajax() that queries the mediawiki API to automatically edit to update a price on a page. If the edit succeeds failed is not defined and the page reloads. If it fails, failed is set to true and it resets the button used to trigger the update.
button is simply a button element, the wg* variables are part of the mediaWiki object here used to access the pagename and url prefix (usually /index.php).
Does anyone know why jshint and jslint seem to think this function should be new GEReqsDone() rather than GEReqsDone()?
Constructors are the only functions in JavaScript that should start with a capital letter. JSLint/JSHint will see that it starts with an uppercase G and assume it is a constructor.
This is the only convention we have to make sure people know that the function should be used as a constructor. Some people write defensively to avoid people missing the new keyword:
var SomeConstructor = function () {
if (!(this instanceof SomeConstructor))
return new SomeConstructor();
}

Categories