I'm attempting to create a function lookup in Javascript essentially mapping a data type to a function that does something for that data type. Right now I have something similar to:
var Namespace = Namespace || {};
Namespace.MyObj = function () {
var stringFunc = function(someData) {
//Do some string stuff with someData
};
var intFunc = function(someData) {
//Do some int stuff with someData
};
var myLookUp = {
'string': stringFunc,
'int' : intFunc
};
return {
PublicMethod: function (dataType, someData) {
myLookUp[dataType](someData);
}
};
} ();
When I invoke Namespace.MyObj.PublicMethod(dataType, someData) I get an error that myLookUp is not defined. I'm assuming I'm not going about setting up the function lookup object correctly, but not sure how to do so. Thanks for any help.
The problem might simply be incorrect case
myLookup[dataType](someData);
should be (notice the capital U)
myLookUp[dataType](someData);
Just looked at my post after I wrote it up, stupid oversight, I'm declaring the properties as strings, instead of just properties.
....
var myLookUp = {
string: stringFunc,
int: intFunc
};
....
Fixes the issue.
Some additional follow up, in my actual code dataType is the result of a jQuery select. Don't know why or if this would be browser dependant (I'm using FireFox), but using double quotes around the property definition works, single quotes does not, and no quotes works as well. :-\
Related
I was tearing my hair out to get this done...particularly for an html5 detection script. I wanted a variable that is set only once and that can't be overwritten again. This is it:
var StaticConfiguration = {};
StaticConfiguration.Main = {
_html5: null
}
StaticConfiguration.getVariable = function(name) {
return StaticConfiguration.Main["_" + name];
}
StaticConfiguration.setVariable = function(name, value) {
if(StaticConfiguration.Main["_" + name] == null) {
StaticConfiguration.Main["_" + name] = value;
}
}
First, I define a global object StaticConfiguration containing all of these variables - in my case, just "html5". I set it to null, since I want to set it inside the application. To do so, I call
StaticConfiguration.setVariable("html5", "true");
It's set then. If I try to set it again, it fails - of course, since _html5 is not null anymore. So I practically use the underscore to "hide" the static variable.
This is helping me a lot. I hope it's a good approach - please tell me if not :)
First off, it's true, not "true" all strings (apart from the empty string) evaluate to true, including the string "false".
Second off, do you really need to protect data like this? There's not really any way to safely run a user's Javascript i your context anyway. There's always a way around protection like this. If offending code really cared, it could just replace the whole StaticConfiguration object anyway.
Matthew's code is a better approach to the problem, but it doesn't follow a singleton pattern, but is a class that needs to be instanciated. I'd do it more like this, if you wanted a single object with "static" variables.
StaticConfiguration = new (function()
{
var data = {}
this.setVariable = function(key, value)
{
if(typeof data[key] == 'undefined')
{
data[key] = value;
}
else
{
// Maybe a little error handling too...
throw new Error("Can't set static variable that's already defined!");
}
};
this.getVariable = function(key)
{
if (typeof data[key] == 'undefined')
{
// Maybe a little error handling too...
throw new Error("Can't get static variable that isn't defined!");
}
else
{
return data[key];
}
};
})();
Personal sidenote: I hate the "curly brackets on their own lines" formatting with a passion!
Take a look at Crockford's article on Private Members in JavaScript. You can do something like this:
var StaticConfiguration = (function() {
var html5; /* this is private, i.e. not visible outside this anonymous function */
return {
getVariable: function(name) {
...
},
setVariable: function(name, value) {
...
}
};
)();
How about:
var StaticConfiguration = new (function()
{
var data = {}
this.setVariable = function(key, value)
{
if(typeof data[key] == 'undefined')
{
data[key] = value;
}
};
this.getVariable = function(key)
{
return data[key];
};
})();
Similar to the other answer, but still allows arbitrary keys. This is truly private, unlike the underscore solution.
I'm a little curious as to why you think that you have to go to this extent to protect the data from being overwritten. If you're detecting the browser, shouldn't it only be done once? If someone's overwriting it with invalid data, then I would assume that it would be a problem in the client implementation and not the library code - does that make sense?
As a side note, I'm pretty big on the KISS principle, especially when it comes to client side scripting.
I know i'm a little late to the party but in situations like this i usually
var data;
if (data === undefined || //or some other value you expect it to start with{
data = "new static value"
};
I have run into some trouble with a piece of backbone code. The code below relates to a render function. I can retrieve all the models. My trouble arises when I try to use the "Collections.where" method at line marked number #1. As you can see, I have passed an object literal into the render function but for some reason I am unable to reference it within the customers.where method on line #1. When I give this method a literal number like 45 it works. Is there some way around this so I can pass the variable reference in?
Thanks alot
render: function(options) {
var that = this;
if (options.id) {
var customers = new Customers();
customers.fetch({
success: function (customers) {
/* #1 --> */ var musketeers = customers.where({musketeerId: options.id});
console.log(musketeers.length) //doesn't work as options.id is failing on last line
var template = _.template($('#customer-list-template').html(), {
customers: customers.models
});
that.$el.html(template);
console.log(customers.models);
}
});
} else {
var template = _.template($('#customer-list-template').html(), {});
that.$el.html(template);
}
}
Although it isn't explicitly documented, Collection#where uses strict equality (===) when searching. From the fine source code:
where: function(attrs, first) {
if (_.isEmpty(attrs)) return first ? void 0 : [];
return this[first ? 'find' : 'filter'](function(model) {
for (var key in attrs) {
if (attrs[key] !== model.get(key)) return false;
}
return true;
});
},
note the attrs[key] !== model.get(key) inside the callback function, that won't consider 10 (a probable id value) and '10' (a probable search value extracted from an <input>) to be a match. That means that:
customers.where({musketeerId: 10});
might find something whereas:
customers.where({musketeerId: '10'});
won't.
You can get around this sort of thing with parseInt:
// Way off where you extract values from the `<input>`...
options.id = parseInt($input.val(), 10);
I was tearing my hair out to get this done...particularly for an html5 detection script. I wanted a variable that is set only once and that can't be overwritten again. This is it:
var StaticConfiguration = {};
StaticConfiguration.Main = {
_html5: null
}
StaticConfiguration.getVariable = function(name) {
return StaticConfiguration.Main["_" + name];
}
StaticConfiguration.setVariable = function(name, value) {
if(StaticConfiguration.Main["_" + name] == null) {
StaticConfiguration.Main["_" + name] = value;
}
}
First, I define a global object StaticConfiguration containing all of these variables - in my case, just "html5". I set it to null, since I want to set it inside the application. To do so, I call
StaticConfiguration.setVariable("html5", "true");
It's set then. If I try to set it again, it fails - of course, since _html5 is not null anymore. So I practically use the underscore to "hide" the static variable.
This is helping me a lot. I hope it's a good approach - please tell me if not :)
First off, it's true, not "true" all strings (apart from the empty string) evaluate to true, including the string "false".
Second off, do you really need to protect data like this? There's not really any way to safely run a user's Javascript i your context anyway. There's always a way around protection like this. If offending code really cared, it could just replace the whole StaticConfiguration object anyway.
Matthew's code is a better approach to the problem, but it doesn't follow a singleton pattern, but is a class that needs to be instanciated. I'd do it more like this, if you wanted a single object with "static" variables.
StaticConfiguration = new (function()
{
var data = {}
this.setVariable = function(key, value)
{
if(typeof data[key] == 'undefined')
{
data[key] = value;
}
else
{
// Maybe a little error handling too...
throw new Error("Can't set static variable that's already defined!");
}
};
this.getVariable = function(key)
{
if (typeof data[key] == 'undefined')
{
// Maybe a little error handling too...
throw new Error("Can't get static variable that isn't defined!");
}
else
{
return data[key];
}
};
})();
Personal sidenote: I hate the "curly brackets on their own lines" formatting with a passion!
Take a look at Crockford's article on Private Members in JavaScript. You can do something like this:
var StaticConfiguration = (function() {
var html5; /* this is private, i.e. not visible outside this anonymous function */
return {
getVariable: function(name) {
...
},
setVariable: function(name, value) {
...
}
};
)();
How about:
var StaticConfiguration = new (function()
{
var data = {}
this.setVariable = function(key, value)
{
if(typeof data[key] == 'undefined')
{
data[key] = value;
}
};
this.getVariable = function(key)
{
return data[key];
};
})();
Similar to the other answer, but still allows arbitrary keys. This is truly private, unlike the underscore solution.
I'm a little curious as to why you think that you have to go to this extent to protect the data from being overwritten. If you're detecting the browser, shouldn't it only be done once? If someone's overwriting it with invalid data, then I would assume that it would be a problem in the client implementation and not the library code - does that make sense?
As a side note, I'm pretty big on the KISS principle, especially when it comes to client side scripting.
I know i'm a little late to the party but in situations like this i usually
var data;
if (data === undefined || //or some other value you expect it to start with{
data = "new static value"
};
String.prototype.parse = function(f) {
alert(this.replace(f, ""));
};
var a = "Hello World";
parse.apply(a, ["Hello"]);
Is the code correct?
No, that’s not correct. The function is defined as String.prototype.parse, so it is not available as parse (in fact, parse is undefined).
You could run it like the following:
String.prototype.parse.apply(a, ["Hello"]);
But actually, the reason why you add the function to the prototype of String is that you extend String objects with that function. So you actually should just run the function like this:
a.parse("Hello");
edit:
Oh, and in response to your question title “Why does this function return as undefined?”: The function doesn’t return anything, because you don’t tell the function to return anything. You could for example define it like this to return the replaced string (instead of alerting it):
String.prototype.parse = function(f) {
return this.replace(f, "");
};
And then you could alert the return value of the function:
alert(a.parse("Hello"));
There is no such variable parse defined in your code sample. If you really want to apply the function later on, you should do this:
// Capture function as a local variable first
var parse = function(f) { alert(this.replace(f, "")); };
String.prototype.parse = parse;
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
}