Get the name of a method stored in a variable - javascript

I have some trouble with getting the name of a method stored in a variable... Here is an exemple of what I want :
Function MyObject(){
this.actualMethod = this.thatName;
}
MyObject.prototype.thatName = function(){}
MyObject.prototype.getActualMethodName = function(){
return this.actualMethod.name; /* This doesn't work since the function itself is anonymous, so this.actualMethod.name doesn't work... I want it to return "thatName" */
}
I tried to navigate through the prototype with my console, in vain... Is there a way to do this ?

You need to name the function:
MyObject.prototype.thatName = function thatName() {};
Or, as you mentioned, you can find its name in the prototype (but I wouldn't suggest you to do it):
for (var key in MyObject.prototype) {
if (MyObject.prototype[key] === this.actualMethod) {
return key;
}
}
But why do you need this? Maybe there could be a better solution.

Related

Javascript Revealing Module Pattern in AngularJS Service not working

I'm using the following code in my angularJS service to get some task done :
angular.factory('promiseFactory', function(){
var artistIds = [];
function setArtistIds(artistIds){
artistIds = artistIds;
}
return {
createPromiseForNotification: promiseFactory,
getNotis: getNotis,
setNotis : setNotis,
//setArtistIds : setArtistIds,
artistIds : artistIds
}
});
This factory is used in another factory notifications.js wherein I'm trying to set
promiseFactory.artistIds = [1,2,3];
on some ajax call but its not working, when I use the artistIds variable in any of the functions of my promiseFactory, it turns out to be blank array [] (the initial value). Why?
Ok, Secondly, this thing works when I use a function called setArtistIds to implement the same thing but even then I have to do something like
function setArtistIds(i){ // Right
artistIds = i;
}
But not when I do it like this :
function setArtistIds(artistIds){ // Wrong
artistIds = artistIds;
}
Can someone please explain me what wrong I'm doing.
When you are executing this line of code:
promiseFactory.artistIds = [1,2,3];
You are only changing property of the object returned by your factory.
But all your methods not even using it, they are using variable artistIds in the closure.
In order to fix this error, add getter and setter to your factory.
When you are naming parameter of the setter function the same way as your closure variable, you are hiding it. That's why it was not working.
Just give it another name.
angular.factory('promiseFactory', function(){
var artistIds = [];
function setArtistIds(newArtistIds){
artistIds = newArtistIds;
}
function getArtistIds(){
return artistIds;
}
return {
createPromiseForNotification: promiseFactory,
getNotis: getNotis,
setNotis : setNotis,
setArtistIds : setArtistIds,
getArtistIds : getArtistIds,
}
});

Get calling arguments for getter in javascript

Given a javascript object like this:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
// access caller name here, so I can return cool/neat stuff
}
});
I want to be able to get children of myThing.gen, but know what is being asked for in the getter.
for example:
var coolThing = myThing.gen.oh.cool;
var neatThing = myThing.gen.oh.neat;
I want the "oh.cool" or "oh.neat" part in getter, so I can make decisions based on this, and return something specific to it. I am ok with solution not working in IE, or old browsers, as it is primarily for node.
The actual purpose of this is so that I can request myThing.gen.oh.neat and have the myThing.gen getter resolve to require('./oh/neat.js') and return it.
Since require cache's, this is an efficient way to dynamically load modular functionality, and have a tidy interface (rather than just dynamically building the require where needed) without having to know the structure ahead of time.
If there is no introspection-of-name function that can get this for me, I could just do something less elegant, like this:
myThing.gen = function(name){
return require('./' + name.replace('.', '/') + '.js');
}
and do this:
neatThing = myThing.gen('oh.neat');
I don't like this syntax as much, though. I looked at chai's dynamic expect(var).to.not.be.empty stuff, but couldn't figure out how to do it completely dynamically. Maybe there is not a way.
without actually solving the problem of dynamically discovering the caller, I can do this:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
return {
'oh':{
'cool': require('./oh/cool.js'),
'neat': require('./oh/neat.js')
}
};
}
});
Is there a way to do this dynamically?
You can't see what the property gen will be used for in the future, so you would need to return an object with properties that react to what the object is used for when it actually happens:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
var no = {};
Object.defineProperty(no, 'cool', {
get: function(){ alert('cool'); }
});
Object.defineProperty(no, 'neat', {
get: function(){ alert('neat'); }
});
return { oh: no };
}
});
Demo: http://jsfiddle.net/UjpGZ/1/

Prevent multiple DOM searches in jquery

I created a function to return me a jquery element.
function GetDialogButton() {
return $('a.dialog');
};
This was done as the same element was used within multiple other functions. I thought it best if it was obtained from a single place, therefore making it easier to change in future should the atribute name change.
I would like to improve this getter so that it does not perform a search everytime when called multiple times within a single page load.
How can I do this? do I cache it? or perhaps there is no need as this is optimised out?
You can create a cache variable, but it will pollute the global namespace again
var dialogButton;
function GetDialogButton() {
if(dialogButton){
return dialogButton;
}
dialogButton = $('a.dialog');
return dialogButton;
};
Creating a global cache variable is not necessary. You can do it without adding a variable to the global scope. Something like this would do:
var GetDialogButton = (function() {
var set;
return function() {
if (set === undefined) {
set = $('a.dialog');
}
return set;
};
}());
Well, you could lazy-load it.
var $dialogButton = null;
function GetDialogButton() {
if($dialogButton == null)
$dialogButton = $('a.dialog');
return $dialogButton
};
Another alternative, if you expect there to only be one dialog button you could give the element an id and then the act of searching for it will be more efficient
<a id="dialogButton">...</a>
$('#dialogButton')... // nice and quick
You could keep the global namespace clean by;
function GetDialogButton() {
if (typeof GetDialogButton.element === 'undefined' ) {
GetDialogButton.element = $("a.dialog");
}
return GetDialogButton.element;
};

How do I verify if several attributes are in a JSON structure within JavaScript?

I am creating a module that takes in several complicated JSON files and would like some code to give the user feedback if certain elements are absent.
Below is the way I am doing it now, but I cannot help to think there must be a cleaner, less hacky way.
var _und = require("underscore");
//this function takes a list of required attributes and ensures they are present
var check_req_attr = function(config, req_attr, callback) {
var config_attr = Object.keys(config);
var absent_attr = _und.difference(req_attr, config_attr); //slightly hacky code that checks to ensure config has correct vars
if (absent_attr.length !== 0) {
throw Error("missing following attributes from config:" + absent_attr);
} else {
callback();
};
};
It just feels...dirty. If there is no real elegant way to do it, I would be open to critiques on my code. Thanks!
Parse the JSON to JS.
var data = JSON.parse(theJson);
Use something like:
function hasKey(obj, key) {
return typeof obj[key] !== 'undefined';
};
function hasKeys(obj, keys) {
for (var i = 1, len = keys.length; i < len; i++) {
if (!hasKey(obj, keys[i])) {
return false;
};
};
return true;
};
Now you can simply do:
if (hasKeys(data, ["firstKey", "secondKey", "thirdKey"]) {
console.log("valid");
};
This should be the way to do it, using every and has:
if (_und.every(req_attr, function(attr) {
return _und.has(config, attr);
}))
throw new Error();
In a native environment, you would just use the in operator:
req_attr.every(function(attr){ return attr in config; })
I think your solution is actually quite elegant! No need for an anonymous function, and the loop (which must happen at some point, obviously) neatly abstracted away with difference.
Two suggestions:
I'd give the function a synchronous signature. No callback argument. There can't be any reason to go async if you honor the function signature (i.e. basing your answer on config and req_attr only).
I'd change the function to return the missing properties (attributes is wrong term). You could also add a requireProperties function that uses this "check" function that would throw if a property was missing. This allows for different kind of uses.
Why don't you try with something like:
obj = JSON.parse(json);
and then check
if(obj.YourProperty == undefined){
//do something..
}
Hope i understood your question.. It should work with complicated JSON files too.. Good luck ;)
You could also use the in operator (requiredAttr in obj):
function objHasAllRequiredAttrs(obj, attrNames) {
return attrNames.reduce(function(memo, attrName) {
return memo && (attrName in obj);
}, true);
}
objHasAllRequiredAttrs({foo:1}, ['foo']); // => true
objHasAllRequiredAttrs({bar:1}, ['foo']); // => false

Change var in object literal function

Hi guys I am writing some code using the object literal pattern, I have function that returns a value:
'currentLocation': function() {
var cL = 0;
return cL;
},
I then need to update the variable 'cL' from another function like this:
teamStatus.currentLocation() = teamStatus.currentLocation() + teamStatus.scrollDistance();
This part is part of another function - however I get an error back stating: invalid assignment left-hand side
I am guessing I can not update the variable in this way, could anyone suggest a better method or point me in the right direction.
Any help would be greatly appreciated.
Going to add more code to highlight what I am trying to do:
'currentLocation': function() {
var cL = 0;
return cL;
},
'increaseTable': function() {
if (teamStatus.currentLocation() <= teamStatus.teamStatusTableHeight() ) {
teamStatus.currentLocation = teamStatus.currentLocation() + teamStatus.scrollDistance();
$("#tableTrackActual").animate({scrollTop: (teamStatus.currentLocation)});
$("#tableMembers").animate({scrollTop: (teamStatus.currentLocation) });
//console.log(teamStatus.currentLocation());
teamStatus.buttonRevealer();
}
}
As you can see increaseTable should update the value of currentLocation - help this sheds more light on what I am trying to achieve.
You're writing teamStatus.currentLocation() =, which calls the function teamStatus.currentLocation and tries to assign to the return value. That isn't valid. You want just teamStatus.currentLocation = — no function call.
The variable inside your function is completely private to that function (and any functions defined within it). If you need to create a number of functions that share a set of private variables, you can do that with a closure. For instance:
var Thing = (function() {
var thingWideData;
function getData() {
return thingWideData;
}
function setData(newData) {
thingWideData = newData;
}
return {
getData: getData,
setData: setData
};
})();
What that does is create a Thing object which has getData and setData functions available for it, which get and set the completely private thingWideData variable contained by the anonymous closure. More about this pattern here and here, although the latter of those is more about private methods than private data.
What your code produces is:
0 = 0 + <some number>
Which variable do you want to update? cL? You are declaring it in the function, you cannot assign a value to it from outside. Depending on the rest of your code, you might be better off with getters and setters:
var object = {
_cL = 0,
get currentLocation() {
return this._cL;
},
set currentLocation(value) {
this._cL = value;
}
}
then you can do:
teamStatus.currentLocation = teamStatus.currentLocation + teamStatus.scrollDistance();
Update:
Regarding IE: If currentLocation should actually be just a number, it might be sufficient to just declare it as property:
var obj = {
currentLocation: 0
}

Categories