I'm trying to sort out if this is plausible but have gotten syntax errors at best. So I am wondering if it is at all possible.
What I have is an object (example only)
var myObj = {
something1_max:50,
something1_enabled:false,
something1_locked:true,
something2_max:100,
something2_enabled:false,
something2_locked:true,
something3_max:10,
something3_enabled:true,
something3_locked:true
}
and what I want to do through a function is do something like again for example to sum things up..
function displayDetails(theScope, obj)
{
console.log(obj.[theScope]_max);
}
(function(){displayDetails('something3', myObj);})()
so when displayDetails() is called whatever the scope I can see in this example the max for that scope. In the console log for the example I would hope to see 10
Properties of JavaScript objects can always be accessed as a string using the bracket syntax, ie object['property']. This, of course, means you can build that string dynamically:
console.log(obj[theScope + '_max']);
Put the property name string in brackets.
console.log(obj[theScope + '_max']);
Related
During my coding I made a mistake by calling a function like this
someFunction( 'abc' [someValue] )
I had forgotten the colon inside the function call.
After I found the error I played around.
An assignment like this does not throw an error as well.
let a = 'abc'[someValue];
I would expect a syntax error here. Is there an explanation for this?
A string in Javascript can behave as an object and, as such has properties such as .length and methods such as .slice. So, for any property access on an object in Javascript, one can use either the dot notation as in:
str.length
or the [] syntax as in:
str["length"]
or using a variable:
let len = "length";
str[len]
So, what you have with:
'abc' [someValue]
Is just that syntax. A string followed by a property access. That is legal Javascript. It attempts to get the property from that object with the name of whatever string is in the someValue variable.
Here's are a couple working examples:
// simple property access
let prop = "length";
console.log("abc"[prop]);
// method call
console.log("one fine day"["slice"](4, 8));
One would not generally code this way with a string, but it's perfectly legal as it's just part of how one can access properties on an object in Javascript.
Because that's not a syntax error. The engine thought you were trying to get a letter from that string, so if someValue was a number it will work perfectly fine
let a = "abc"[0]
console.log(a, "abc"[1]) //a, b
I have a function that would use other variables, depending on what has been passed.
Like this = ActionBar(slot) slot contains "one".
and I would like to create a call inside that like object.slot.name but it should convert it before hand to make the command look like object.one.name. Is there a way to do this in javascript/jquery?
I remember vaguely that some other language does this as {slot} or something like that.
Sorry if this question was already asked, I've checked google and stackoverflow too, but didn't find an answer.
Also I'd like to know what's the proper programming term for this kind of variable passing?
Edited it cause of misunderstandings. I'm looking into OOP js, so object is an object, one is an object, and name is an attribute, but when passing I'm passing "one" as a string to the function.
Tried eval, it doesn't work while dotted with an object.
Source code:
function disableActionButton(slot){
$("#"+slot).attr("disabled","disabled")
gcd = player.slot.gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
$("#"+slot).removeAttr("disabled").css("color","black").val(player.slot.name);
}, player.slot.gcd*1000)
}
It's really unclear what your current structure is (much clearer now you've posted code, see "update" below), but fundamentally the way to do this sort of thing in JavaScript is to have a container object. (If you don't already have one, introduce one.) Then slot can refer to a property of that object, like this:
var container = {
one: "This is one",
two: "This is two"
};
// ...
function foo(slot) {
console.log(container[slot]);
}
// ...
foo("one"); // ends up logging "This is one"
foo("two"); // ends up logging "This is two"
This works because the container object has properties, which in JavaScript can be referred to in two different ways:
Using dot notation and a literal name, e.g. container.one, or
Using bracketed notation and a name in a string, e.g. container["one"].
They're exactly equivalent except where the property name comes from. And of course, in the second case, the property name needn't be a literal string, it can be the result of any expression, including a variable reference (e.g., you can get the name from slot).
This works with all object properties, including properties that refer to functions. I mention this only because you mentioned functions in your question, so if you need to, you can do this:
function foo(slot) {
container[slot]();
}
...which calls the function on container that the property with the name held by the slot argument. So if slot is "one", it does container.one().
Update:
Your source directly echos the container example above, just apply the above to it:
function disableActionButton(slot){
$("#"+slot).attr("disabled","disabled")
// ---------v----v---- here
gcd = player[slot].gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
// ------------------------------------------------------------ and here--v----v
$("#"+slot).removeAttr("disabled").css("color","black").val(player[slot].name);
// ------v----v------- and here
}, player[slot].gcd*1000)
}
Or, rather than looking up the slot data each time, grab it once and reuse it:
function disableActionButton(slot){
// Grab it once...
var slotdata = player[slot];
$("#"+slot).attr("disabled","disabled")
// ---vvvvvvvvv--- then use it
gcd = slotdata.gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
$("#"+slot).removeAttr("disabled").css("color","black").val(slotdata.name);
}, slotdata.gcd*1000)
}
There's no special name for this. You're passing a property name into a function, and the function is looking up the property on the player object using that name. In some other languages this might be called "reflection" but the term doesn't really apply to dynamic languages like JavaScript.
can someone tell me if this is valid javascript? I know you couldnt do this sort of thing in c# but js is a much looser language..
var arrayToUse = "arr" + sender.value;
for (i = 0; i <= arrayToUse.length; i++) {
// something..
}
specifically - the dynamic generation of the array name..
update..
so i have an array called arrMyArray which is initialised on document ready. sender.value = "MyArray" - but could be something else eg MyArray2
I want to dyanimcally iterate over the array that is indicated by the sender.value value.
Yes, this is entirely valid.
arrayToUse will be a string (regardless of the value of sender.value — it will be converted to a string), and i will iterate from 0 to the string's length).
One minor note: it should be for (**var** i = 0; …), otherwise i will be treated as a global variable, which will almost certainly end badly if you've got multiple loops running at the same time.
Edit: you want to get the array based on the name? In that case you've got to look it up in whatever context the array is defined.
If it's a global array, use window.
For example:
var arrayName = "arr" + sender.value;
var array = window[arrayName];
…
To get a variable name defined by a variable, you need to use eval, like so:
var arrayToUse = eval("arr" + sender.value);
However, you must be very careful with this, because controlling sender.value would allow someone to hijack your entire application this way. You should usually try to find another solution.
If the variable is defined at the globally, you can look it up as window["arr" + sender.value] instead. This is still not ideal, but is less of a security risk.
What you need to do is access a variable with the name "arr" + sender.value. Accessing the variable whose contents are "arr + sender.value doesn't do what you want -- that's just a string.
To access the variable with that name, you can look it up as a global (globals are members of the window object in the browser):
window["arr" + sender.value]
This is safer and faster than using eval() because it doesn't run code in a JavaScript execution context to evaluate the string -- it just looks up a variable in the window object with that name.
i want to create a dynamic generated form using javascript, everything works fine, until i try to pass an array as parameter. When i do this, an error happens. Coulr anyone explain what this is?
Heres my code:
var loadFrm = function(component) {
for(nItem in component) {
var myComponent = "add" + firstToUpper(component[nItem].type);
var callComponent = myComponent + "(" + component[nItem].opt + ");";
eval(callComponent);
}
}
var json = [
{
type: "scale",
opt: {content: [{label: "male", value: "m"}, {label: "female", value: "f"}]}
}
];
loadFrm(json);
Edit Here's the error:
missing ] after element list
[Break on this error] addScale([object Object]);
If you use a debugger to look at the string callComponent, you'll probably find it looks something like this:
addScale([object Object])
...which isn't what you want. That's because you're effectively calling toString on your opt object, and the default toString on objects just looks like that. The eval error is because that's invalid syntax.
Generally speaking, any time you think you need to use eval, there's almost certainly a better answer. In this case, it looks like you're trying to call a function and pass in opt. Assuming these functions are "globals", you can do that like this:
var loadFrm = function(component) {
var nItem, functionName;
for (nItem = 0; nItem < component.length; ++nItem) {
functionName = "add" + firstToUpper(component[nItem].type);
window[functionName](component[nItem].opt);
}
}
Live example
Notes on the above:
Don't use for..in to loop through arrays unless you really know what you're doing. for..in does not enumerate the indexes of an array, it enumerates the properties of an object.
We look up the function by name using window[functionName]. This works because "globals" are actually properties of the window object, and you can look up properties using a string name for them using bracketed notation.
Having gotten the function via window[functionName], we just call it directly, passing in the object opt rather than a string form of it. I assume addScale expects to see an object.
I moved all of the vars to the top of the function because that's where they really are (details).
If you can, I'd recommend moving addScale and the related functions to their own object rather than putting them on window. The window namespace is already pretty crowded. Here's the live example modified to not add any symbols to window at all, instead putting the addScale function on an object called functions and using it from there.
Off-topic: The syntax var loadFrm = function(component) creates an anonymous function that it then assigns to a variable. This is used a lot, but unless you're creating different functions based on a condition, e.g.:
var f;
if (...) {
f = function() { ... };
}
else {
f = function() { ... };
}
...it's not actually useful. (If you are creating different functions based on a condition like that, then it's not only useful, it's necessary.) I recommend using named functions whenever possible, because a function with a name helps your tools help you by showing you the function name in error messages, call stacks, etc.
Off-topic 2: You have a variable called json, but FYI, it's not using JSON notation. It's using a combination of JavaScript array and object literal notation, which is a superset of JSON. You'll see a lot of people confused about this, I mention it because you said you're new and so it's worth nipping in the bud. :-) JSON is purely a notation. (A very useful one.)
Use this:
fn = eval(functionName);
fn(objParameter)
someFunction(link) {
someOtherFunction('div' + link);
}
By calling someFunction("Test"), the string "divTest" gets passed to someOtherFunction(). But I want the value of the variable "divTest" to be passed.
How can that be done?
Make your variables members of an object. Then you can use [] to access the objects members using a string:
var byname = {
divabc: ...,
divxyz: ...
};
function someFunction(link) {
someOtherFunction(byname['div'+link]);
}
someFunction('abc'); // calls someOtherFunction(byname.divabc)
For this kind of dynamic construction/access of variable names you should use the alternative object notation where:
object.member === object["member"]
This way you could construct your variable name as a string and use it inside square brackets for accessing object members.
eval will do this, but it's usually indicative of some other problem with the program when you want to synthesize identifiers like this. As Ionut says it's better to use the [] notation. I like to link to this whenever questions like this come up.
You should be able to accomplish this with the 'eval' function.
Try this:
var divFoo = "bar";
function someFunction(link) {
someOtherFunction(this['div' + link]);
}
function someOtherFunction(value) {
alert(value);
}
someFunction("Foo");
As wybiral said, all you need is eval:
someFunction(link) {
someOtherFunction(eval('(div' + link + ')');
}
Basically what it does is evaluates the contents of a string as code. Obviously eval is a dangerous little tool since it allows executing arbitrary code so take care when using it.