Check if an ES6 class exist by name - javascript

I'm lazy loading part of my code, some file containing classes that are then called in other parts, so I wrote a simple code that checks if a class instance exists and then execute it, or retry after 100ms.
let checkExist = setInterval(function() {
if (typeof(ClassInstanceName) === "object") {
ClassInstanceName.DoSomething();
clearInterval(checkExist);
}
}, 100);
This code works, but I need to generalize it in a self contained function
function WaitForClass(args) {
let instance = (args.instance === undefined ? "" : args.instance);
let callback = (args.callback === undefined ? "" : args.callback);
if (instance == "" || callback == "") {
console.log("Error -> " + instance + " " + callback);
}
else {
if (document[instance]) {
//it never find the instance
callback();
}
else {
setInterval(function() {
WaitForClass(args);
}, 100);
}
}
}
WaitForClass({instance:"ClassInstanceName", callback:function(){ ClassInstanceName.DoSomething();}});
The function is simple, but can't make it work.
For compatibility with other code portions I need to check if the instance exist using a string containing the name, and not just the object representing it.

Related

Why do I have to IF return, IF what?

I am learning to code or rather - even reading the code at this moment.
Could anyone please explain me, why those lines are there and what do they do?
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
What is the purpose of those two lines?
function handleCardClick(e) {
// you can use event.target to see which element was clicked
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
let currentCard = e.target;
currentCard.style.backgroundColor = currentCard.classList[0];
if (!card1 || !card2) {
currentCard.classList.add("flipped");
card1 = card1 || currentCard;
card2 = currentCard === card1 ? null : currentCard;
}
if (card1 && card2) {
noClicking = true;
// debugger
let gif1 = card1.className;
let gif2 = card2.className;
if (gif1 === gif2) {
cardsFlipped += 2;
card1.removeEventListener("click", handleCardClick);
card2.removeEventListener("click", handleCardClick);
card1 = null;
card2 = null;
noClicking = false;
} else {
setTimeout(function() {
card1.style.backgroundColor = "";
card2.style.backgroundColor = "";
card1.classList.remove("flipped");
card2.classList.remove("flipped");
card1 = null;
card2 = null;
noClicking = false;
}, 1000);
}
}
if (cardsFlipped === COLORS.length) alert("game over!");
}
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
The lines below those 2 lines will not be executed if one of the 2 lines are returned.
It means if noClicking == true or e.target.classList.contains("flipped") == true, then all the lines below those 2 lines will not be executed.
While the answers already given are correct, I thought it could help to understand why those lines are there in place. They are called guard clauses. Their purpose is to make your code more efficient.
Think of a scenario like this:
function myFunc(someParam) {
/*
do something that takes a lot of time/resources
... then somewhere you find someParam was invalid!
so all the calculations done until now was useless
*/
}
So instead of checking the validity of arguments, global variables, etc. when you need them in the function, you check for them in the beginning of the function such as like this:
function myFunc(someParam) {
//let's say valid() is a function that checks for validity of the param,
//returns true if valid, false if invalid.
if(!valid(someParam)) return;
/*
do something that takes a lot of time/resources
... then your function will only run the expensive code
if it is sure that there are no invalid arguments passed to it.
*/
}
It doesn't always have to be just return. This is your choice. Maybe the function always returns some positive number, then you could return -1 as such:
const getRoot = (num) => {
if(num < 0) return -1;
//get square root of the number
return abs(Math.sqrt(num));
}
//Then when you call the function, you could check if the result is not -1,
//to make sure you passed the correct arguments.
if (getRoot(-1) < 0)
console.error("Uh oh, you passed a negative number to the square root function");
Or you could throw an Error:
function myFunc (someParam) {
if(!valid(someParam)) throw new Error("wrong param bruh");
//do something...
}

Define this function outside of a loop

I have the following code :
for (var entry in metadata) {
if (metadata.hasOwnProperty(entry)) {
var varName = metadata[entry].variableName;
if (metadata[entry].multipleValues === "false") {
if (angular.isDefined(vm[varName]) && (vm[varName] !== null) && vm[varName].id !== null) {
filters.push(factory.buildEntry(metadata[entry].variableName, vm[varName].id, null, factory.filterOperators.textContains));
}
} else {
if (angular.isDefined(vm[varName]) && (angular.isArray(vm[varName])) && (vm[varName].length > 0)) {
filters.push(factory.buildEntry(metadata[entry].variableName, null, vm[varName].map(function (item) {
return item.id;
}), factory.filterOperators.textContains));
}
}
}
}
But SonarQube keeps telling me to Define this function outside of a loop., and the only function I have inside this loop is the anonymous function I pass to the Array.prototype.map() method :
function (item) {
return item.id;
}
Which would be useless if I define it outside my loop since it's body only contains one line of code.
Why I'm getting this error ? and how can I tell SonarQube to skip it.
How about you define it outside the loop
var mapFunction = function (item) {
return item.id;
};
for (var entry in metadata) {
if (metadata.hasOwnProperty(entry)) {
var varName = metadata[entry].variableName;
if (metadata[entry].multipleValues === "false") {
if (angular.isDefined(vm[varName]) && (vm[varName] !== null) && vm[varName].id !== null) {
filters.push(factory.buildEntry(metadata[entry].variableName, vm[varName].id, null, factory.filterOperators.textContains));
}
} else {
if (angular.isDefined(vm[varName]) && (angular.isArray(vm[varName])) && (vm[varName].length > 0)) {
filters.push(factory.buildEntry(metadata[entry].variableName, null, vm[varName].map(mapFunction), factory.filterOperators.textContains));
}
}
}
}
You can assign functions to variables and then treat that variable as a function
var foo = function(){console.log('bar')};
foo();
In your case by assigning your mapping function to a variable, then passing that variable to the .map() gives you also an efficiency boost, because the function doesn't have to be re-instantiated every single time the loop runs. It can just re-use the same function over and over.
And as soon as the enclosing function ends which executes the loop, the variable ceases to exist.

Alternate structure for a sequence of If statements?

I'm programming a poker program in JavaScript. I have a Hand class that has the properties "cards", "value" and "valueCards". The value property is an integer that corresponds to a hand type, and the valueCards is the array of five cards that also corresponds to the hand type. For example, if my original seven cards(contained in the cards property) contains a flush, this.value will flip to 6, and this.valueCards will equal only the five cards that equal the highest flush.
I have one method for each hand type, and ALL of them change the value and valueCards if that hand type is detected. I have an accessor method for value called getValue, so when I went to make a method to run all the tests on a hand and keep the highest one, it came out looking like this:
POKER.Hand.prototype.getTrueValue = function () {
this.testStraightFlush();
if(this.value == POKER.HAND_TYPE.STRAIGHT_FLUSH){ return; }
this.testQuads();
if(this.value == POKER.HAND_TYPE.QUADS){ return; }
this.testFullHouse();
if(this.value == POKER.HAND_TYPE.FULL_HOUSE){ return; }
this.testFlush();
if(this.value == POKER.HAND_TYPE.FLUSH){ return; }
this.testStraight();
if(this.value == POKER.HAND_TYPE.STRAIGHT){ return; }
this.testTrips();
if(this.value == POKER.HAND_TYPE.TRIPS){ return; }
this.testTwoPair();
if(this.value == POKER.HAND_TYPE.TWO_PAIR){ return; }
this.testPair();
if(this.value == POKER.HAND_TYPE.PAIR){ return; }
this.getHighCards();
};
I mean, the method works fine. It just bothers me, like maybe I should be doing it a different way. Does this go against convention?
If you change your this.test* functions to return true if the "hand" is found, or return false if not - then you could do something as ugly, yet somehow satisfying, as
POKER.Hand.prototype.getTrueValue = function () {
this.testStraightFlush() ||
this.testQuads() ||
this.testFullHouse() ||
this.testFlush() ||
this.testStraight() ||
this.testTrips() ||
this.testTwoPair() ||
this.testPair() ||
this.getHighCards();
};
or
change your this.test* functions to check only if this.found is false, and set this.found = true if a hand is found, so you'd simply
POKER.Hand.prototype.getTrueValue = function () {
this.found = false;
this.testStraightFlush();
this.testQuads();
this.testFullHouse();
this.testFlush();
this.testStraight();
this.testTrips();
this.testTwoPair();
this.testPair();
this.getHighCards();
};
Not an answer but I would redesign your functions :
Each method should return the prop itself :
function testFlush ()
{
if (...) return POKER.HAND_TYPE.FLUSH;
return null;
}
function testStraightFlush()
{
if (...) return POKER.HAND_TYPE.StraightFlush;
return null;
}
This way , you'll be able to get both value and check for truness.
POKER.Hand.prototype.getValue= function ()
{
return this.testFlush () || testStraightFlush()
};
Just for the fun of it, you could redesign the tests like this:
POKER.Hand.prototype.getTrueValue = function () {
var tests = [
[ "testStraightFlush", POKER.HAND_TYPE.STRAIGHT_FLUSH ],
[ "testQuads" , POKER.HAND_TYPE.QUADS ],
[ "testFullHouse" , POKER.HAND_TYPE.FULL_HOUSE ],
... etc...
];
for (var test in tests) {
var fun = this[tests[test][0]];
var val = tests[test][1];
fun();
if (this.value == val) {
return;
}
}
this.getHighCards();
};
Or the functions might simply return a boolean, so you could have a simpler tests array
var tests = [
"testStraightFlush",
"testQuads" ,
"testFullHouse" ,
... etc...
];

How to accomplish this without using eval

Sorry for the title but I don't know how to explain it.
The function takes an URI, eg: /foo/bar/1293. The object will, in case it exists, be stored in an object looking like {foo: { bar: { 1293: 'content...' }}}. The function iterates through the directories in the URI and checks that the path isn't undefined and meanwhile builds up a string with the code that later on gets called using eval(). The string containing the code will look something like delete memory["foo"]["bar"]["1293"]
Is there any other way I can accomplish this? Maybe store the saved content in something other than
an ordinary object?
remove : function(uri) {
if(uri == '/') {
this.flush();
return true;
}
else {
var parts = trimSlashes(uri).split('/'),
memRef = memory,
found = true,
evalCode = 'delete memory';
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
memRef = memRef[dir];
evalCode += '["'+dir+'"]';
}
else {
found = false;
return false;
}
if(i == (parts.length - 1)) {
try {
eval( evalCode );
} catch(e) {
console.log(e);
found = false;
}
}
});
return found;
}
}
No need for eval here. Just drill down like you are and delete the property at the end:
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
if(i == (parts.length - 1)) {
// delete it on the last iteration
delete memRef[dir];
} else {
// drill down
memRef = memRef[dir];
}
} else {
found = false;
return false;
}
});
You just need a helper function which takes a Array and a object and does:
function delete_helper(obj, path) {
for(var i = 0, l=path.length-1; i<l; i++) {
obj = obj[path[i]];
}
delete obj[path.length-1];
}
and instead of building up a code string, append the names to a Array and then call this instead of the eval. This code assumes that the checks to whether the path exists have already been done as they would be in that usage.

Have a javascript function privately track it's number of calls

I'm trying to figure out how I can have a javascript function privately track the number of times it has been called. The objective is to be able to query this value in the console during debugging by doing func.run
My first attempt:
function asdf() {
if (!asdf.run) {
asdf.run = 0;
} else {
asdf.run++;
console.error('run: ' + asdf.run);
}
console.error('asdf.run def: ');
console.error(asdf.run);
}
asdf();
This is a good lesson of why one should ALWAYS aim to use === in nearly all javascript booleans, cause they could secretly be ==
Closures are the way to go here:
var asdf = (function () {
var runs = 0;
var f = function () {
++runs;
// your function here
};
f.runs = function () {
return runs;
};
return f;
}());
Usage:
asdf();
asdf();
asdf.runs(); // 2
asdf();
asdf.runs(); // 3
Or, you could use a mocking framework like (shameless self plug) Myrtle.
Your first try would work fine except you've forgotten that 0 is a "falsy" value in JavaScript, so on the first run and every run thereafter !this.run will evaluate to true and your else block will never be reached. This is pretty easy to work around.
function foo() {
if(typeof(foo.count) == 'undefined') {
foo.count = 0;
} else {
foo.count++;
}
console.log(foo.count);
}
foo(); # => 0
foo(); # => 1
foo(); # => 2
# ...
I haven't actually tried this, but I looked up "static function variables in JavaScript", and I found this resource. I think the main difference between what you wrote and what's in that solution is how the first run of the function is detected. Perhaps your !asdf.run test is not working the way you thought it was, and you should use typeof asdf.run == 'undefined' to test instead.
OK, here is a method that I came up with that does not require the function to be modified at all.
So if you have this.
function someFunction() {
doingThings();
}
you could add a counter like this...
addCounter(this, "someFunction");
where this is the scope you are in, you could use any object that has a method you want to count.
Here's the code for it.
<html>
<head>
<script>
function someFunc() {
console.log("I've been called!");
};
// pass an object, this or window and a function name
function wrapFunction(parent, functionName) {
var count = 0, orig = parent[functionName];
parent[functionName] = function() {
count++;
return orig.call(this, Array.prototype.slice(arguments));
}
parent[functionName].getCount = function() {
return count;
};
}
var someObj = {
someFunc: function() {
console.log("this is someObj.someFunc()");
}
}
wrapFunction(this, "someFunc");
wrapFunction(someObj, "someFunc");
someFunc();
someObj.someFunc();
someObj.someFunc();
someObj.someFunc();
console.log("Global someFunc called " + someFunc.getCount() + " time" + (someFunc.getCount() > 1 ? "s" : "")) ;
console.log("Global someObj.someFunc called " + someObj.someFunc.getCount() + " time" + (someObj.someFunc.getCount() > 1 ? "s" : "")) ;
</script>
</head>
So, !asdf.run is a form of the double equals operator == and I had set asdf.run to 0 so it was false.
Using the triple equals === :
typeof asdf.run === "undefined" for the boolean solves my issue.
So a final usable and useful version:
function sdf() {
if (typeof sdf.run === "undefined") { sdf.run = 0; }
sdf.run++;
}
To query the number of times sdf has been called:
sdf.run;
To actually make this variable private and protect it from change, one would implement a closure.
//using a closure and keeping your functions out of the global scope
var myApp = (function() {
//counter is a private member of this scope
var retObj = {}, counter = 0;
//function fn() has privileged access to counter
retObj.fn = function() {
counter++;
console.log(counter);
};
//set retObj to myApp variable
return retObj;
}());
myApp.fn(); //count = 1
myApp.fn(); //count = 2
myApp.fn(); //count = 3
You don't necessarily need a closure. Just use a static variable.
var foo = function(){
alert( ++foo.count || (foo.count = 1) );
}
// test
function callTwice(f){ f(); f(); }
callTwice(foo) // will alert 1 then 2
or
callTwice( function bar(){
alert( ++bar.count || (bar.count = 1) );
}); // will alert 1 then 2
the second one is a named anonymous function. And note this syntax:
var foo = function bar(){ /* foo === bar in here */ }

Categories

Resources