I'm trying to create an array that maps strings to variables. It seems that the array stores the current value of the variable instead of storing a reference to the variable.
var name = "foo";
var array = [];
array["reference"] = name;
name = "bar";
// Still returns "foo" when I'd like it to return "bar."
array["reference"];
Is there a way to make the array refer to the variable?
Put an object into the array instead:
var name = {};
name.title = "foo";
var array = [];
array["reference"] = name;
name.title = "bar";
// now returns "bar"
array["reference"].title;
You can't.
JavaScript always pass by value. And everything is an object; var stores the pointer, hence it's pass by pointer's value.
If your name = "bar" is supposed to be inside a function, you'll need to pass in the whole array instead. The function will then need to change it using array["reference"] = "bar".
Btw, [] is an array literal. {} is an object literal.
That array["reference"] works because an Array is also an object, but array is meant to be accessed by 0-based index. You probably want to use {} instead.
And foo["bar"] is equivalent to foo.bar. The longer syntax is more useful if the key can be dynamic, e.g., foo[bar], not at all the same with foo.bar (or if you want to use a minimizer like Google's Closure Compiler).
Try pushing an object to the array instead and altering values within it.
var ar = [];
var obj = {value: 10};
ar[ar.length] = obj;
obj.value = 12;
alert(ar[0].value);
My solution to saving a reference is to pass a function instead:
If the variable you want to reference is called myTarget, then use:
myRef = function (newVal) {
if (newVal != undefined) myTarget = newVal;
return myTarget;
}
To read the value, use myRef();. To set the value, use myRef(<the value you want to set>);.
Helpfully, you can also assign this to an array element as well:
var myArray = [myRef];
Then use myArray[0]() to read and myArray[0](<new value>) to write.
Disclaimer: I've only tested this with a numerical target as that is my use case.
My solution to saving a reference is to pass a function instead:
If the variable you want to reference is called 'myTarget', then use:
myRef = function (newVal) {
if (newVal != undefined)
myTarget = newVal;
return myTarget;
}
To read the value, use myRef();. To set the value, use myRef(value_to_set);.
Helpfully, you can also assign this to an array element as well:
var myArray = [myRef];
Then use myArray0 to read and myArray[0](value_to_set) to write.
Disclaimer: I've only tested this with a numerical target as that is my use case.
Related
I would like to access the object provided only it's string path in form of array is known.
1.) there is an object, where
root["obj1"]["obj2"] = 1;
(in common case root["obj1"]...["objN"])
2.) I have ONLY string objectPath known:
var objectPath = 'root["obj1"]["obj2"]'
3.) I need NOT only READ the object, but SET it's value, like
objectPath = 2;
//so root["obj1"]["obj2"] === 2
As I understand
there might be some options with eval(), but it gets the value, not the variable;
one can loop through all objects of root, make convertion to "root.obj1.obj2" (which is not the case, as "obj1" can easily be "obj with spaces1") and check if given string equals to current object in the loop.
http://jsfiddle.net/ACsPn/
Related Link:
Access object child properties using a dot notation string
I wrote a function for you, trying to make it as pretty and reusable as possible :
function setProp(path, newValue, holder) {
var t = path.split(/[\[\]"]+/).filter(function(v){return v}),
l = t.pop(), s, o = holder || window;
while (s = t.shift()) o = o[s];
o[l] = newValue;
}
You use it like this :
setProp('root["obj1"]["obj2"]', 2);
If your root object isn't in a global variable, pass the relevant holder as third argument.
Demonstration (open the console to see the changed root object)
I need to store an object in localStorage - and I know that in order to do so, I have to convert the object into a string. All cool.
My problem is in actually creating the object in the first place: I have two values in sessionStorage that need to be added to the object which is then passed into localStorage. However, when I try to create the object, one value is being stored as the variable name rather than its (numeric) value. Any idea whats going on here?
var siteName = sessionStorage['1'];
var siteID = (+sessionStorage['2']);
var temp = {siteID:siteName};
alert(typeof siteID);
alert(JSON.stringify(temp));
The first alert confirms that siteID is indeed a number type, but the second alert shows that the variable name (siteID) is stored rather than its numeric value.
This line:
var temp = {siteID:siteName};
...creates an object containing a property called siteId with the value taken from the siteName variable.
If you want the property name to be taken from the siteID variable instead:
var temp = {};
temp[siteID] = siteName;
Or in ES2015 (aka "ES6") you could use the new computed property name syntax:
// ES2015+ only!
var temp = {[siteId]: siteName};
In JavaScript, you can access/create properties on objects in two different but equal ways: Using dotted notation with a literal property name:
obj.foo = "bar"; // Creates a `foo` property on `obj` with the value `"bar"`
...or using bracketed notation and a string:
obj["foo"] = "bar"; // Does the same thing
The keys in object initializers like your var temp = {siteID:siteName}; are always used literally (although they can optionally be in quotes); there's no way with an object initializer to have a key taken from a variable instead. So you have to do it as a two-step process, first create the object, then set the property.
So, if you do
temp[siteID] = siteName;
...the number in siteID will be converted to a string and will become the property name, with the value of siteName being the value.
var temp = {};
var key = 1;
temp[key] = "value";
console.log(temp[1]); // "value"
console.log(temp["1"]); // "value"
(Property names are always strings in JavaScript [for now].)
Change it to this.
var temp = {};
temp[siteName] = siteID;
Or if the typeof test was meant to show the property name, you'd reverse them.
var temp = {};
temp[siteID] = siteName;
But be aware that siteID is considered a String from that point forward.
I'm trying to use a string as a reference to a variable to pass into a function. For example:
var names = ['Peter', 'John'],
var hasName = function(name){
var params = ['names'];
return $.inArray(name, eval( params[0] )) === -1;
};
How to avoid eval()?
EDIT:
The string from params[0] is comming from a data-qval of an input in my html. The array that contains the actual data can be declared anywhere, params[0] is just a reference to that array passed in as string in data-qval, it's a parameter. I pasted my plugin's code here .
http://pastebin.mozilla.org/1598528 Line 101.
Full example: http://jsfiddle.net/elclanrs/ZsS2D/29/
It currently works, I'm just looking for a way get rid of eval()...
In that particular case, just use names:
var names = ['Peter', 'John'],
var hasName = function(name){
var params = ['names'];
return $.inArray(name, names ) === -1;
};
(See also the note below.) (Your edit makes the above not applicable.)
If you're trying to look up the names array in some container using the string "names", you'd have to have a reference to the container, e.g.:
var obj = {
names: ['Peter', 'John'
};
var hasName = function(name){
var params = ['names'];
return $.inArray(name, obj[params[0]] ) === -1;
};
If there is no container other than the variable scope in which you're doing this, you'll have to use eval. But you can (and usually should) adjust things so you have a container (as above) so you can avoid it. Note that if names is declared at global scope, you do have a container (window).
So to summarize:
If names is a var at global scope (or an implicit global), window[params[0]] will give you a reference to it.
If names is already in some container object, you can use container[params[0]] to get a reference to it.
If names is a var within a function, you cannot get at it using a runtime string without eval; ideally, rather than var names = [...];, use var container = {names: [...]}; and then you can use container[params[0]].
Note that your function is called hasName, but it returns true when the array doesn't have the name and false when it does. You probably want !== -1, not === -1.
Isn't this enough?
var hasName = function(name){
return $.inArray(name, names) > -1;
};
Also, notice the comparison
Because JavaScript treats 0 as loosely equal to false (i.e. 0 ==
false, but 0 !== false), if we're checking for the presence of value
within array, we need to check if it's not equal to (or greater than)
-1.
Strings as references to variables? If it's a global object in a browser, it will be in the window object, so you can just do window[variableName] to get its value. Same for objects, i.e. instead of object.foo, you can do object['foo'] or bar = 'foo', object[bar]. For locally scoped variables, you cannot do it without using an object or eval.
if names is global, you can use the global namespace, i.e. window
var hasName = function(name,namespace){
namespace = namespace || window;
return $.inArray(name, namespace.names) > -1;
};
hasName('Peter'); //=> true;
This may also be an idea:
var MYNS = { names:['Peter','John']
,hasName: function(name){
return $.inArray(name, this.names) > -1;
}
};
MYNS.hasName('Peter'); //=>true
It's difficult to explain the case by words, let me give an example:
var myObj = {
'name': 'Umut',
'age' : 34
};
var prop = 'name';
var value = 'Onur';
myObj[name] = value; // This does not work
eval('myObj.' + name) = value; //Bad coding ;)
How can I set a variable property with variable value in a JavaScript object?
myObj[prop] = value;
That should work. You mixed up the name of the variable and its value. But indexing an object with strings to get at its properties works fine in JavaScript.
myObj.name=value
or
myObj['name']=value (Quotes are required)
Both of these are interchangeable.
Edit: I'm guessing you meant myObj[prop] = value, instead of myObj[name] = value. Second syntax works fine: http://jsfiddle.net/waitinforatrain/dNjvb/1/
You can get the property the same way as you set it.
foo = {
bar: "value"
}
You set the value
foo["bar"] = "baz";
To get the value
foo["bar"]
will return "baz".
You could also create something that would be similar to a value object (vo);
SomeModelClassNameVO.js;
function SomeModelClassNameVO(name,id) {
this.name = name;
this.id = id;
}
Than you can just do;
var someModelClassNameVO = new someModelClassNameVO('name',1);
console.log(someModelClassNameVO.name);
simple as this
myObj.name = value;
When you create an object myObj as you have, think of it more like a dictionary. In this case, it has two keys, name, and age.
You can access these dictionaries in two ways:
Like an array (e.g. myObj[name]); or
Like a property (e.g. myObj.name); do note that some properties are reserved, so the first method is preferred.
You should be able to access it as a property without any problems. However, to access it as an array, you'll need to treat the key like a string.
myObj["name"]
Otherwise, javascript will assume that name is a variable, and since you haven't created a variable called name, it won't be able to access the key you're expecting.
You could do the following:
var currentObj = {
name: 'Umut',
age : 34
};
var newValues = {
name: 'Onur',
}
Option 1:
currentObj = Object.assign(currentObj, newValues);
Option 2:
currentObj = {...currentObj, ...newValues};
Option 3:
Object.keys(newValues).forEach(key => {
currentObj[key] = newValues[key];
});
I've got a feeling this might not be possible, but I would like to determine the original variable name of a variable which has been passed to a function in javascript. I don't know how to explain it any better than that, so see if this example makes sense.
function getVariableName(unknownVariable){
return unknownVariable.originalName;
}
getVariableName(foo); //returns string "foo";
getVariableName(bar); //returns string "bar";
This is for a jquery plugin i'm working on, and i would like to be able to display the name of the variable which is passed to a "debug" function.
You're right, this is very much impossible in any sane way, since only the value gets passed into the function.
This is now somehow possible thanks to ES6:
function getVariableName(unknownVariableInAHash){
return Object.keys(unknownVariableInAHash)[0]
}
const foo = 42
const bar = 'baz'
console.log(getVariableName({foo})) //returns string "foo"
console.log(getVariableName({bar})) //returns string "bar"
The only (small) catch is that you have to wrap your unknown variable between {}, which is no big deal.
As you want debugging (show name of var and value of var),
I've been looking for it too, and just want to share my finding.
It is not by retrieving the name of the var from the var but the other way around : retrieve the value of the var from the name (as string) of the var.
It is possible to do it without eval, and with very simple code, at the condition you pass your var into the function with quotes around it, and you declare the variable globally :
foo = 'bar';
debug('foo');
function debug(Variable) {
var Value = this[Variable]; // in that occurrence, it is equivalent to
// this['foo'] which is the syntax to call the global variable foo
console.log(Variable + " is " + Value); // print "foo is bar"
}
Well, all the global variables are properties of global object (this or window), aren't they?
So when I wanted to find out the name of my variables, I made following function:
var getName = function(variable) {
for (var prop in window) {
if (variable === window[prop]) {
return prop;
}
}
}
var helloWorld = "Hello World!";
console.log(getName(helloWorld)); // "helloWorld"
Sometimes doesn't work, for example, if 2 strings are created without new operator and have the same value.
Global w/string method
Here is a technique that you can use to keep the name and the value of the variable.
// Set up a global variable called g
var g = {};
// All other variables should be defined as properties of this global object
g.foo = 'hello';
g.bar = 'world';
// Setup function
function doStuff(str) {
if (str in g) {
var name = str;
var value = g[str];
// Do stuff with the variable name and the variable value here
// For this example, simply print to console
console.log(name, value);
} else {
console.error('Oh snap! That variable does not exist!');
}
}
// Call the function
doStuff('foo'); // log: foo hello
doStuff('bar'); // log: bar world
doStuff('fakeVariable'); // error: Oh snap! That variable does not exist!
This is effectively creating a dictionary that maps variable names to their value. This probably won't work for your existing code without refactoring every variable. But using this style, you can achieve a solution for this type of problem.
ES6 object method
In ES6/ES2015, you are able to initialize an object with name and value which can almost achieve what you are trying to do.
function getVariableName(unknownVariable) {
return Object.keys(unknownVariable)[0];
}
var foo = 'hello';
var output = getVariableName({ foo }); // Note the curly brackets
console.log(output);
This works because you created a new object with key foo and value the same as the variable foo, in this case hello. Then our helper method gets the first key as a string.
Credit goes to this tweet.
Converting a set of unique variable into one JSON object for which I wrote this function
function makeJSON(){ //Pass the variable names as string parameters [not by reference]
ret={};
for(i=0; i<arguments.length; i++){
eval("ret."+arguments[i]+"="+arguments[i]);
}
return ret;
}
Example:
a=b=c=3;
console.log(makeJSON('a','b','c'));
Perhaps this is the reason for this query
I think you can use
getVariableName({foo});
Use a 2D reference array with .filter()
Note: I now feel that #Offermo's answer above is the best one to use. Leaving up my answer for reference, though I mostly wouldn't recommend using it.
Here is what I came up with independently, which requires explicit declaration of variable names and only works with unique values. (But will work if those two conditions are met.)
// Initialize some variables
let var1 = "stick"
let var2 = "goo"
let var3 = "hello"
let var4 = "asdf"
// Create a 2D array of variable names
const varNames = [
[var1, "var1"],
[var2, "var2"],
[var3, "var3"]
]
// Return either name of variable or `undefined` if no match
const getName = v => varNames.filter(name => name[0] === v).length
? varNames.filter(name => name[0] === v)[0][1]
: undefined
// Use `getName` with OP's original function
function getVariableName(unknownVariable){
return getName(unknownVariable)
}
This is my take for logging the name of an input and its value at the same time:
function logVariableAndName(unknownVariable) {
const variableName = Object.keys(unknownVariable)[0];
const value = unknownVariable[variableName];
console.log(variableName);
console.log(value);
}
Then you can use it like logVariableAndName({ someVariable })