Is this Javascript object literal key restriction strictly due to parsing? - javascript

Please refer to the code below, when I "comment in" either of the commented out lines, it causes the error (in IE) of "':' expected". So then is my conclusion correct, that this inability to provide a reference to an object value, as an object key in a string literal; is this strictly an interpreter/parsing issue? Is this a candidate for an awful (or at least "bad") "part" of Javascript, in contrast to Crockford's "good parts"?
<script>
var keys = {'ONE': 'one'};
//causes error:
//var obj1 = {keys.ONE: 'value1'};
//var obj1 = {keys['ONE']: 'value1'};
//works
var obj1 = {};
obj1[keys.ONE] = 'value1';
//also works
var key_one = keys.ONE;
var obj2 = {key_one: 'value1'};
</script>

The limitation of the literal object syntax is that the names has to be literal. As the names can be specified as an identifer as well as a string, it's not possible to use a variable instead.
This will create an object with a property n, not a property answer:
var n = 'answer';
var o = { n: 42 };

You cannot use variables as keys when defining object with {}
Therefore they are being interpreted as string names and can consist only of characters avaliable for variable names
the
objectname[anythingThatReturnsValue]='value1'; is the way to go.
ALSO
You can generate a string and parse it
var s='{"'+keys.ONE+'": "value1"}';
var obj=JSON.parse(s);
//or
s='var obj2='+s;
eval(s);
Both above methods are bad practices for creating objects in JavaScript and I don't recommend them.

Think about it: if it were to work the way you want it would totally introduce a language ambiguity.
var obj = {something:"red"}
var obj = {"something":"red"}
The two statements are equivalent in JavaScript, because bareword keys are "autoquoted." So if something means the literal string "something", how it could also refer to the variable "something". It can't. So if you want to use variables they have to go in square bracket notation instead of key : value notation.

You can try:
var obj = {};
var val = 'foo';
obj[val] = 'bar';
obj.foo >>> 'bar';

Related

How to get a hash table or record type in Javascript without any name space collision?

In JavaScript it is common to use objects as hashes:
hash = {};
hash.key = 'value';
It is even possible to use keys with spaces:
hash['a key'] = 'a value';
But there are several limitations: a key must not be called
__proto__,
constructor,
hasOwnProperty,
isPrototypeOf,
propertyIsEnumerable,
toLocalString,
toString,
valueOf,
__defineGetter__,
__defineSetter__,
__lookupGetter__,
__lookupSetter__,
because this will cause a name space collision with the internals of JavaScript objects.
What is the best work around to circumvent this limitation?
You can use Object.create and set parent as null, for example
var data = {};
console.log(
data.toString
); // in parent prototype there is toString method. returns function
var hash = Object.create(null);
console.log(
hash.toString,
hash.valueOf,
hash.__defineGetter__
); // will be undefined because we set parent as null

Creating variable with constructor

I was looking around and saw this page where they were using String and Array constructors while creating their variables.
How does this differ from not using them?
Example:
var str = "string"; // How I'd normally do it.
var str = new String("string"); // How they did it.
var arr = ["Array", "Item"]; // How I'd normally do it.
var arr = new Array("Array", "Item"); // How they did it.
How exactly do these two differ?
var str = "string"; // typeof string
This is represented as block of memory, use it if you don't want to call a member on it
var str = new String("string"); // typeof object
This is a boxed object, which is slightly more resource consuming, but if you call i.e.
"Hello".length;
The JS parser must first create the boxed object from the string memory and then call the method, which is even slower.
The arrays syntax are always boxed objects in JS: [] is just syntax shorthand for new Array() AFAIK. Um, almost: see the zzzzBov's comment below.

Why this Variable does not pass correctly in JQuery

I have a simple JQuery Statement...and my question is, why in the world does one of these fail?
Lets assume the variable colorAttribute is color
$(thisCLass).css( "color", '#'+hex ); // Works when written
$(thisCLass).css( colorAttribute, '#'+hex ); // Works with variable
$(thisCLass).css({ "color" : '#'+hex }); // Works when written
$(thisCLass).css({ colorAttribute : '#'+hex }); // Does not Work with variable
Any ideas as to why the one fails?
That's because you can't use a variable to specify a name in an object literal.
An identifier in an object literal can be written with or without quotes, so it won't be interpreted as a variable in either case. The object will end up with the identifier that you specify:
{ "colorAttribute" : '#'+hex }
You can use a variable to set a property in an object, but then you have to create the object first and use the bracket syntax:
var obj = {};
obj[colorAttribute] = '#'+hex;
$(thisCLass).css(obj);
because the second one becomes an object with just one property: "colorAttribute".
you should do this:
myobj = {};
myobj[collorAttribute] = "#"+hex;
$(thisClass).css(myobj);
perhaps you're a python programmer, but javascript is not like that regarding dicts (objects here). it happens often.
Object literals/initializers take identifier keys just for their name, not for any values they may represent as a variable. So...
{ colorAttribute: '#' + hex }
...defines an Object with a key named "colorAttribute".
You'll have to use bracket notation to name a key based on a variable:
var css = {};
css[colorAttribute] = '#' + hex;
$(thisClass).css(css);
It doesn't work because you simply cannot do that in JavaScript. In an object literal, the left side of a property declaration is either a string literal or an identifier. If it's an identifier, then the identifier itself is used as if it were a string literal.
You can create an object however and populate a property from a variable:
var cssProps = {};
cssProps[colorAttribute] = '#' + hex;
$(thisClass).css(cssProps);
You can't declare a javascript object literal with a variable for the property name. A property name in a literal must be the actual property name, not a variable.
Instead, if you want to use a variable in the object form, you'd have to construct the object first and then pass it in:
var obj = {};
obj[colorAttribute] = '#'+hex;
$(thisCLass).css(obj);
When you are doing { colorAttribute : '#'+hex } you are creating a new object with a property named "colorAttribute".
I don't know exactly what you need but you could try
var cssObject = {};
cssObject[colorAttribute] = '#'+hex;
//cssObject[otherAttribute] = 'otherValue';
$(thisCLass).css(cssObject);
Hope this was helpfull.
You need a step before writing what you are trying to do here:
First create a variable:
var color = new Object();
color.colorAttribute = '#'+hex
$(thisCLass).css(color);

Use key's value as key in key-value pair in Javascript

How can you use the value of a key-value pair as the key in a different key-value pair in javascript?
I'd like to do the following:
var gizmos = {gizmo1: "G1"};
var things = {gizmos.gizmo1: "T1"};
So that things essentially equals:
var things = {"G1": "T1"};
Like this:
var gizmos = {gizmo1: "G1"};
var things = {};
things[gizmos.gizmo1] = "T1";
There's no way to do it as part of the object initializer (aka object "literal"), you have to do it after.
The reason it works is that in JavaScript, you can access (get or set) a property on an object in two ways: Either using dotted notation and a literal, e.g. foo.bar, or using bracketed notation and a string, e.g. foo["bar"]. In the latter case, the string doesn't have to be a string literal, it can be the result of any expression (including, in this case, a property lookup on another object).
Side Note: If you change gizmos.gizmo1 after you do the things[gizmos.gizmo1] = "T1"; line, it does not change the name of the property on things. There's no enduring link, because the value of gizmos.gizmo1 was used to determine the property name during the things[gizmos.gizmo1] = "T1"; line (just like it is in any other expression).
var gizmos = {gizmo1: "G1"};
var things = {};
things[gizmos.gizmo1]="T1";
To get the value for a given key on an object use object["key"] or object.key

Creating json keys on the fly

I would like to create a json object to send as a post array, but I need to create the key on the fly
var id = $('#myInput').val();
var post = {
'product[123]': 'myValue', // this works fine - but isn't dynamic
'product['+id+']': 'myValue' // this does not work
}
Sending it in as a string works fine, but I get an issue when I want to make it more dynamic. Am I missing something really simple here, or am I trying to do something Javascript isn't supposed to do?
(Note that this has nothing to do with JSON. You're not using JSON there, you're using an object initializer. JSON is a textual (not code) format, which is a subset of JavaScript's object initializer syntax.)
Do it outside the object initializer, using [] notation:
var id = $('#myInput').val();
var post = {};
post[product[id]] = 'myValue';
That will take the value (at runtime) of product[id] and use that as the key for the property. If you wanted the key to literally be product[123] when id is 123, you'd use this instead:
post['product[' + id + ']'] = 'myValue';
A more generic discussion:
var a = "foo";
var obj = {};
obj[a] = "bar";
console.log(obj.foo); // "bar"
JavaScript allows you to specify property keys in two ways: Using dotted notation and a literal (obj.foo), or using bracketed notation and a string (obj["foo"]). In the latter case, the string doesn't have to be a string literal, it can be the result of any expression.
Try
post['product[' + id + ']'] = 'myValue';
Why do you use '[ ]' in ids of the object? Avoid to do this.
In your sample, you can do this by the following code:
var id = $('#myInput').val();
var post = {
'123': 'myValue',
id: 'myValue'
}
Or, if you realy realy want to use an arrry (actually, all objects ARE array in JavaScript).
You can write this:
var product=[];
product['123']='something';
product[id]='another';

Categories