Overriding a Javascript method only if it does not exist - javascript

My goal here is to override a method if it isn't found, otherwise use the original method (for backwards compatibility of a library I can't alter).
This is what I have so far, but am still struggling with:
this.grid.getDataSource = function(){
if (typeof this.grid.getDataSource.getDataSource == "undefined")
return this.grid.getDataSource.getStore();
else return this.grid.getDataSource.getDataSource();
}
I want to have getDatasource() check if it exists, if not, call getStore(). If it does exist, just use the original getDatasource(). I know this breaks because I haven't figured out how to reference the parent 'this' scope. When I work around that issue I get into a recursive loop as it keeps trying to override itself. If you have a better way of doing this please let me know!

i think this should do what you want.
this.grid.getDataSource =
this.grid.getDataSource.getDataSource || this.grid.getDataSource.getStore;
this statement will try to find something that evaluates truish from left to right. when it finds that thing, it will use it as the value for the assignment. in this case if getDataSource is undefined it'll evaluate as false, and getStore will be checked. getStore exists so it'll evaluate to (roughly) true, and so the function reference will be assigned to this.grid.getDataSource.getDataSource;

If you're sure that getDataSource() will not throw an exception, you can try
this.grid.getDataSource.getDataSource = function(){
try {
return this.getDataSource();
}
catch(ex) {
return this.getStore();
}
};
or you can just change
if (typeof this.getDataSource == "undefined")
to
if (typeof this.getDataSource != "function")
UPDATE:
Does this work?:
this.grid.getDataSource = function(){
if (typeof this.getDataSource != "function")
return this.getStore();
else
return this.getDataSource();
}

Related

OOP Question About Vanilla JS: The class's constructor won't accept the variable I'm feeding it as a parameter

I'm trying to learn OOP through practice, but I'm pretty stuck at this point.
This is the code:
const itemEdit = () => {
let editIndex = buttonObj.editArr.indexOf(editID);
console.log(`the editIndex outside of the class is ${editIndex}`);
if (typeof editIndex != "undefined") {
editText = new htmlTextualizer(editIndex);
console.log(
"new class successfully created as variable is not 'undefined' type"
);
}
editText.printOut();
This is the class/constructor:
class htmlTextualizer {
constructor(curr) {
this.curr = curr;
}
printOut() {
console.log(this.curr);
}
}
The output is either 'undefined' or nothing at all. The logic generally works outside of the function, so I suspect it's something to do with the scope of initiation, but I simply fail to work my way around it. Assistance would be much appreciated. Thanks.
JavaScript's indexOf() returns -1 if no match is found. That check should look something like this:
if (editIndex > -1) {…}
I'm not sure if that will resolve your problem or not, but it's a problem in general.
Also, if that if statement is not true, and if editText is not defined somewhere outside what you've pasted here, there will be an error because editText is undefined (and doesn't have methods available).
There are several things that are unclear about your example, since you reference several undefined objects: buttonObj.editArr, editID, editText.
In general, I would approach testing for existence more carefully. You don't want to attempt to access the indexOf method on something undefined.
I'm not sure what your business logic is exactly, but here is how to do what I think it is: always create the new object, unless buttonObj.editArr contains editID.
Here is how to do that:
const itemEdit = () => {
if ( !buttonObj ||
!buttonObj.editArr ||
(typeof buttonObj.editArr !== "object") ||
!editID ||
(buttonObj.editArr.indexOf(editID) < 0) ) {
editText = new htmlTextualizer(buttonObj.editArr.indexOf(editID));
console.log("creating instance of class htmlTextualizer");
}
}

Checking if parameter is a contructor or an instance in javascript

I wanna do the following, if the parameter passed is a contructor, then do new 'constructor' if not, just use the instance. How can I do that?
This is what I've done so far, but it doesn't work. I think something is wrong with my code:
JS
var showList = function (view, options) {
// checking if view is a conctructor or not
if (view instanceof view) {
app.getRegion('main').show(view(options));
} else {
app.getRegion('main').show(new view(options));
}
}
so the above function can be used as:
var listView = new ListView;
showList(listView);
or straight:
showList(new ListView);
I think you're going to want to test whether the argument is an object or a function:
if (typeof view === "function")
will tell you it's a function (a constructor function in your context)
if (typeof view === "object")
will tell you that it's an already constructed object.
var showScreen = function (view, options) {
// check if view is already an object
if (typeof view === "object") {
app.getRegion('main').show(view(options));
} else {
app.getRegion('main').show(new view(options));
}
}
One thing I'm confused about in your code is if view is already an object, then why do you do view(options). That doesn't make sense to me. Doing new view(options) when view is a function makes sense, but not the other option so I think something also needs to be corrected with that line of code. Do you perhaps mean to call a method on that object?
FYI, I tend to avoid using instanceof as a general practice if there is another option because instanceof can have issues with cross frame code whereas typeof does not have those issues.
var showScreen = function (view, options) {
// checking if view is a conctructor or not
if (view instanceof Function) {
app.getRegion('main').show(new view(options));
} else {
app.getRegion('main').show(view(options));
}
}
Maybe not the best way but well.
function A(){}
var a = new A();
a instanceof A // true
a instanceof Function // false
A instanceof Function // true
This seems like a code smell to me. I think it's better pass an instance instead of a constructor function.
In this case you can do:
showScreen(new ListView(options))
If it's hard to construct a ListView you should wonder why that is.

Restoring a nullified function back in JavaScript

I was simply practicing a little bit of JavaScript. My goal was to create a function that can call another function with the .invoke() until .revoke() is called, which then nullifies the function.
Later on, I've added .porcupine() which was, in theory, supposed to take the firstly invoked function (in this case, alert()) and then reapply it to the original "temp". The issue is, though, after being revoked temp becomes unknown, therefore it can not call anything anymore. Is there something very obvious to this that I'm missing out or will the solution have to be fairly messy?
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
return {
invoke: function(x) {
return unary(x);
},
revoke: function() {
var nullifier = unary;
unary = null;
return nullifier.apply(this, arguments);
},
porcupine: function() {
unary = denullifier;
return unary.apply(denullifier, arguments);
}
};
};
console.log('----------');
temp = revocable(alert);
temp.invoke(7); ///alerts 7
temp.revoke();
temp.porcupine(); //exception
temp.invoke(7); //doesn't get here
I don't quite understand what you're doing, but there are a few problems with your code.
if (denullifier === null)
denullifier = unary;
denullifier is not null here, it's undefined - so the condition isn't met.
return nullifier.apply(this, arguments);
You can't call alert this way, the first param must be null or window.
return unary.apply(denullifier, arguments);
The same.
This is your problem:
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
denullifier is undefined when declared without a value. However, you are checking for type-strict equality with null, which will be false, so denullifier is never set and porcupine is not able to restore the unary function.
I'd suggest:
Use == instead of === to get equality with undefined
Even better, use typeof denullifier != "function"
Or, (although I don't know your design) you should not make denullifier a global, static variable that will be shared amongst revocable instances, but instead make it instance-specific by putting the declaration inside the function body.

Correctly way to find some variable with 2 case

I want to find some variable from 2 different element patterns.
var something = $('.class').attr('data-something');
if(typeof something === 'undefined') {
var something = $('.class').attr('data-another');
}
if(typeof something != 'undefined') {
// do action...
console.log(something);
}
I just want to get some data from attr data-someting="mydata"
And if data-someting="mydata" not found so find a data form data-another
Then do action....
Im doing right ? or another correctly way to do better ?
Whats about Try Catch ?
Some browsers will have it undefined while some will return false. So, here is a more robust version:
if (typeof something === 'undefined' || something === false) {
// try another attribute
} else {
// do your stuff
}
Update:
Hm, accroding to the doc:
As of jQuery 1.6, the .attr() method returns undefined for attributes
that have not been set.
So, probably, they are explicitly ensuring this themselves as of 1.6 and my information about false is outdated. In this case your own code is perfectly correct.
You can/should access data properties using $.data();
e.g
var something = $('.class').data('something');
var something = $('.class').attr('data-something') || $('.class').attr('data-another')
This will do for both undefined and false values

How to correctly determine if key exists in multidimensional javascript object using a recursive function

I am trying to create a recursive function that will loop through a multidimensional object and test whether the key exists in a separate object. If the key does not exist I want to break the loop and return false, if all the keys exist I want to return true.
The problem I am having is that the function always seems to be returning true. Here is the code I am using:
var properties = {'global': {'structure' : {'body': {}}}};
var testExists = {'global': {'structure': {'test': 'value'}}};
if( ! this.exists(properties, testExists)) {
console.log("DOESNT EXIST");
}
exists: function(destination, source) {
var exists = true;
check:
for (var property in source) {
if(destination[property]) {
arguments.callee(destination[property], source[property]);
}
else
{
exists = false;
break check;
}
}
console.log(exists);
return exists;
},
When I view the console to see the value of 'exists' I see two line the first false the second is true, so there must be an error with the recursion I am creating
Your problem seems to be that you don't use the result of the recursively called function.
Also, you shouldn't use arguments.callee, but a function name, and potentially check for the parameters to be objects before enumerating their properties. And you might want to check also for properties of destination that are not in the enumerated source.
Try this:
function equal(destination, source) {
if (Object(destination)!==destination || Object(source)!==source)
// at least one of them is a primitive value
return destination == source; // maybe use strict equality === ?
for (var prop in source)
if (!(prop in destination) || !equal(source[prop], destination[prop]))
return false;
return true;
}
You're making it more complicated than it needs to be:
function exists(destination, source) {
for (var property in source) {
if(destination.hasOwnProperty(property)) {
if (!exists(destination[property], source[property])) {
return false;
}
} else {
return false;
}
}
return true;
}​
Note that .hasOwnProperty means that this will only compare direct properties of the objects and not those inherited from prototypes. I assumed that this was what you were looking for.
Also note: it actually uses the result of the recursive calls, it recurses properly, it uses .hasOwnProperty instead of just checking falsiness, and it doesn't use intermediate variables to store the result (which wouldn't work in a recursion the way you were using them, anyway).
One more thing: This will only go "one way," i.e. any properties in the destination that are not in the source will not be checked. To check both ways, you have to call it twice or extend it to loop over both.

Categories

Resources