This works:
handleOnChange(e) {
this.setState({[e.target.id]: e.target.value});
}
e.target.id is wrapped in brackets ([ ]), while e.target.value is not.
I could write e.target.value in brackets too and it would work, but if I remove the brackets from e.target.id my code will not work. Why?
I did some research and believe this is because Computed Property Names (I am not sure though), but then the question arises, why does the property of e.target.id needs to be computed while e.target.value does not? Both of them are simply values I would think.
why does the property of e.target.id needs to be computed while e.target.value does not?
The right hand side is always a value (and always has been).
The left hand side is, historically, a string or identifier. The ability to put an expression there (a computed property name) is a new feature.
const foo = "bar";
// Here the property name is foo because it is an identifier
const obj = {
foo: foo
};
console.log(obj);
// Here the property name is foo because it is a string
const obj2 = {
"foo": foo
};
console.log(obj2);
// Here the property name is bar because it computed by evauating the constant
const obj3 = {
[foo]: foo
};
console.log(obj3);
// Here the property name is barbar because it computed by evauating function call that returns a template string that uses the constant twice
function blah() {
return `${foo}${foo}`;
}
const obj4 = {
[blah()]: foo
};
console.log(obj4);
//This is the same as the previous example except that because the right hand side is always a value, wrapping the code in square brackets means it is treated as an array literal (as opposed to being a computed property which is what square brackets mean on the left hand side)
function blah() {
return `${foo}${foo}`;
}
const obj5 = {
[blah()]: [foo]
};
console.log(obj5);
I could write e.target.value in brackets too and it would work, but if I remove the brackets from e.target.id my code will not work. Why?
Those two pair of brackets serve very different purpose: in
{ [keyName]: value }
you have indeed a computed property name. In
{ keyName: [value] }
however, the brackets around [value] create an array.
Because {foo.bar: "fizz"} doesn't mean the same thing as {"foo.bar": "fizz"}, in fact that isn't even syntactically correct.
const a = {b: "c"};
const foo = {a.b: "d"}; // error
console.log(foo);
also consider:
const foo = {
bar: "other"
};
const b = {
[foo.bar]: "fizz", // Computed
"foo.bar": "buzz", // String accessor
// foo.bar: "err" // Syntax error
};
console.log(b);
You want the value of foo.bar to be used as the key for the Object. The language mechanism for doing that is to either extract the value and then use brackets to dereference it:
const buzz = {};
buzz[foo.bar] = "fizz";
or you use the new language feature to make it a one-liner:
const buzz = {[foo.bar]: "fizz"};
Related
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 })
I want to create an javascript object, which value of "C" copies value of "A" :
var obj={
'A':'some complex function returns a string',
'C':obj['A']
};
But it has errors. I try to check if key 'A' really created:
var f=function(str){
console.log(str);
return str;
};
var obj={
[f('A')]:[f('B')],
"C":obj['A']
};
which prints
B
A
and then errors. Which means 'A' created but it still says obj['A'] is not defined. Why would that happen?
Your current attempt obviously fails because by the time the code constructs new object the value of obj variable was not assigned yet.
You could check it by using
var obj = { C: typeof obj}
I want to create an javascript object, which value of "C" copies value of "A"
If you want C to always reflect the value of A you could use
var obj = {
A: 'Some value',
get C() {
return this.A;
}
}
Or split obj declaration
var obj = { A: 'Some Value' };
obj.C = obj.A
You get the error because obj was not yet defined when you attempted to acces it from inside of it.
To make your code work you could use a getter.
The get syntax binds an object property to a function that will be
called when that property is looked up. - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
Also you do not need quotes for your object properties.
Quotes can be omitted if the property name is a numeric literal
or a valid identifier name.
var obj = {
A : 'Hello',
get C() {
return this.A;
}
};
console.log(obj.C);
You can not reference a variable that has not created yet. You can do it like this.
var obj = { 'A' : 'some complex function returns a string' }
obj['C'] = obj['A']
I can not understand why after destructuring assignment, items prop does not equal Gorilla.
It will be used after deleting the main prop items: "Piggi" in the origin object options. I do not understand why...
'use strict';
let options = {
size: 100,
items: "Piggi"
}
let { title="Menu", items:w="Gorilla", size } = options;
let a = title;
let b = w;
console.log(a + " - " + b); // must be "Menu - Gorilla"
In the destructuring declaration with initialization here:
let { items:w = "Gorilla" } = options;
the syntax means to declare a variable called "w", whose value should be initialized to the value of the property called "items" in the object referenced by "options", or if there is no such property then to the string "Gorilla".
In your case, then, the variable "w" is initialized to the value of the "items" property in the original object.
If you don't want to take the value from the source object, then don't:
let w = "Gorilla";
When you analyze the code, you get three techniques working here:
short hand properties
{ foo, bar }
for
{ foo: foo, bar: bar}
default values
{ foo = 42 }
which is
{ foo: foo = 42 }
change of the target in the Object Property Assignment Pattern [You Don't Know JS: ES6 & Beyond, Chapter 2: Syntax]:
The syntactic pattern here is source: target (or value: variable-alias).
{ foo: bar }
The synthesis is a new target w for the old property items with a default value of 'Gorilla'.
let options = {
size: 100,
items: "Piggi"
}
let { title="Menu", items:w="Gorilla", size } = options;
let a = title;
let b = w;
console.log(a + " - " + b);
Solution- The problem is , we are overwriting the global object. it is why you have titile as Menu but option object does not have titile property. So, when you assign global object with option,
it still has items as "piggi"
plus you cannot assign object like this, you have to reassign each property in javascript.
i hope you got your answer.
I'm currently running a series of functions where the first argument is a variable defined elsewhere, and the second argument is a string that happens to be identical to the variable name:
assignString(Hello, 'Hello')
assignString(World, 'World')
assignString(Foo, 'Foo')
assignString(Bar, 'Bar')
...
Ideally I would like to simplify this to something like this:
['Hello', 'World', 'Foo', 'Bar'].forEach(() => { assignString... })
or
[Hello, World, Foo, Bar].forEach(() => { assignString... })
Is this actually possible?
const vars = { Hello, World, Foo, Bar };
Object.keys(vars).forEach(key => assignString(vars[key], key));
I think the only way you could dynamically create variables based on a string value is by doing something like this:
var exampleStringValue = 'HELLO';
window[exampleStringValue] = exampleStringValue;
console.log(window.HELLO);
// or, since window is the global context in the browser
console.log(HELLO)
I honestly can't say I can dream up a use-case where that's a good practice, but I don't know your use-case, so no judgement here :)
I'd also like to point out this little library that I've found useful for creating objects where the keys have same value as the name of the key: https://github.com/STRML/keyMirror. I've found that to be used pretty heavily in the React community.
Since the variable name and the string are equivalent, there's no need to pass it in twice. I'd rather pass in the scope of the variable. You could do this so it works in whatever scope you're in:
function assignString(scope, val){
scope[val] = val;
}
Called like
assignString(window, "Hello");
Output of console.log(Hello) ==> "Hello"
Using the new ES6 Map object, we can create name/value pairs in a structure that can then be turned into an Array, so forEach can work:
// Variables that assignString will need:
var Hello = "var1", World = "var2", Foo = "var3", Bar = "var4";
// Map object that contains name of variables and strings that match variable name
var m = new Map([[Hello, "Hello"],[World,"World"],[Foo, "Foo"], [Bar, "Bar"]]);
// Turn Map into Array so forEach will work:
var a = Array.from(m);
// Call forEach which calls assingString and passes key name
// (variable name) and string value
a.forEach((value) => { assignString(value[0], value[1]); });
See this fiddle: https://jsfiddle.net/qnwsajes/34/
You can create an object with your data, iterate over the keys, and pass the key-value-pair to your assignString function.
var data = {
Hello: Hello,
World: World,
Foo: Foo,
Bar: Bar
}
Object.keys(data).forEach(key => assignString(data[key], 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 })