Javascript: access an object property whose name starts with a number - javascript

I'm creating a Javascript / jQuery application.
I need to process a JSON response that represents a HashMap, like this:
{
"accounts": {
"MediaFire": {
"provider": "MediaFire",
"usedStorage": "779680",
"totalStorage": "53687091200"
},
"4Sync": {
"provider": "4Sync",
"usedStorage": "620692",
"totalStorage": "16106127360"
}
}
}
I use a pasing function (which I can't control), which returns the parsed JSON response in an object result.
When I try to access the 4Sync like this:
var usedStorage = result.accounts.4Sync.usedStorage; //doesn't work
it doesn't work, I think it's because of the 4 at the beginning... The same operation with the other object works fine:
var usedStorage = result.accounts.MediaFire.usedStorage; //works
I know the result object contains the object 4Sync, but I can't access it. Here is a screenshot of Chrome's console:
Is there any workaround to solve this?

Use square brackets:
var usedStorage = result.accounts["4Sync"].usedStorage;
Property identifers can begin with a number, but member expressions with the . character will only allow valid variable identifiers (since anything else is ambiguous). To get around this, you can use the square bracket syntax, which is equivalent but allows the use of any string.
If you're interested, here is the grammar:
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
Notice how square brackets can contain any expression, but the . can only be followed by an IdentifierName (basically, any valid identifier, plus reserved words in ES5).

Related

Javascript Object Attribute With/Without quotes [duplicate]

This question already has answers here:
What is the difference between object keys with quotes and without quotes?
(5 answers)
Closed 4 years ago.
I am a JavaScript learner and want to know what is the difference between
var obj1 = {
attribute1 : 1
};
var obj2 = {
"attribute1" : 1
};
console.log(obj1.attribute1);
console.log(obj2.attribute1);
Both of them prints 1. Is there a major difference among them?
They are equivalent in your case.
Internally, they are the same.
What could change is the way you can access them with your code.
When using strings (quoted properties), you can actually use more exotic names for your properties :
var obj3 = {
"attribute with space": 1,
"123AttributeStartingWithANumber": 1,
}
In my example, you cannot access those attribute names via the obj1.attributeName syntax (but you can with the brackets notations : obj1["attribute with space"] or obj1["123AttributeStartingWithANumber"] .
This is because "attribute with space" or "123Attribute" are not valid identifiers in JS.
Note that in your example you can also use the bracket notation :
console.log(obj1["attribute1"]);
console.log(obj2["attribute1"]);
In summary, to quote deceze's comment :
Quoted properties and bracket notation always work, unquoted
properties and . dot access is shorthand for when your property name
is a valid identifier.
There is no difference.
Object literal syntax allows you to use a string or an identifier to provide the property name.
A string allows you to use characters (such as or .) which are not allowed in an identifier, but attribute1 has none of those characters in it.
You can make object keys with space in them if you declare them as strings:
var obj1 = {
attribute1 : 1 // but you cannot say my attribute1: 1 it will throw syntax error
};
var obj2 = {
"my attribute1" : 1
};
console.log(obj1.attribute1);
console.log(obj2.attribute1);

Arguments before a colon

I'm trying to pass an argument to a function in Javascript. However, the argument column is being interpreted as a literal string as opposed to an argument to the function. This is due to the colon directly following the argument column:
update(column, selected) {
var cols = {...this.props.columns, column: selected}
this.props.dispatch(updateColumns({type: "UPDATE_COLUMNS", cols}))
}
I've tried using arguments[0] instead of column but then I am told arguments is a reserved word in strict mode. Any idea how I can get read this value as an argument as opposed to a string?
In modern JavaScript environments, object initializer syntax allows for expressions to be evaluated on the left side of the property initialization:
update(column, selected) {
var cols = {...this.props.columns, [column]: selected}
this.props.dispatch(updateColumns({type: "UPDATE_COLUMNS", cols}))
}
The square brackets mean that the expression inside should be evaluated, and the result should be used as the property name.
In older environments, you'd have to do it in a separate statement, but since you're already using spread syntax I'd guess you're not concerned with that.

Why is this json example an object is parsed as an array [duplicate]

This question already has answers here:
JavaScript property access: dot notation vs. brackets?
(17 answers)
Closed 8 years ago.
I have this JSON code :
{
"query": {
"pages": {
"-1": {
"ns": 0,
"title": "StackOverflow",
}
}
}
}
I parsed it into a JSON object :
data = JSON.parse(jsonString);
Why to access the object -1 I must do data.query.pages[-1] not data.query.pages.-1. In this example pages is not an array but an object.
It's not an array, it's an object. Both object["name"] and object.name are identical ways of accessing a property called name on the given object.
You cannot access an object property with object.-1, simply because that's a syntax error, the same way you can't use object.+1 or object.[1 or object./1. They're all valid names for a property of an object, but they're syntactically invalid when using object.propertyName syntax.
The other caveat is that you cannot have property names which are integers. Setting or getting object[-1] is identical to object["-1"] as the property name is converted to a string. It would be identical to accessing object.-1 if that were valid syntax.
You can't do data.query.pages.-1 for the same reason you can't do var -1;: -1 is not a valid identifier.
But that's not a problem.
foo.bar // Access member bar of object foo
is just a shortcut for
foo["bar"] // Access member bar of object foo
so you can do
data.query.pages["-1"]
You could even do
data["query"]["pages"]["-1"]
Bracket notation has nothing to with arrays, it's just another way to access properties. In fact, the reason why we can only use bracket notation for arrays is because of the evaluation rules: To use dot notation, the property name must be a valid identifier name.
Or simply put:
You can only use dot notation if the property name would be a valid variable name or a reserved word.
And -1 doesn't fall in that category (you can't do var -1 = 'foo'; for example).
Examples for invalid identifier names:
0foo, -foo, &bar
anything that doesn't start with a letter, _ or $
foo-bar, foo+bar, foo bar
anything that contains something that is not a letter, a digit, _ or $ (or fall into specific unicode ranges, see the spec).
However, using reserved words is possible, even though they can't be used as variables:
foo.if // valid
var if = 42; // invalid

javaScript reserved keywords

I am wondering how JavaScript's reserved keywords / functions are managed.
Example:
According to:
http://www.quackit.com/javascript/javascript_reserved_words.cfm
delete is a reserved keyword by JavaScript.
Then consider the following snippet for some context:
var cookieManager = {
get: function (name) {
// function contents ...
console.log("cookieManager.get() called");
return true;
},
set: function (name, value, days) {
// function contents ...
console.log("cookieManager.set() called");
return true;
},
delete: function (name) {
// function contents ...
console.log("cookieManager.delete() called");
return true;
}
};
This object has a delete property, yet the name of it is reserved by JavaScript so it should fail, right?
Yet when I execute cookieManager.delete(); in the webconsole of FireFox I get the following output, suggesting that it works fine:
[11:26:00.654] cookieManager.delete();
[11:26:00.656] cookieManager.delete() called
[11:26:00.657] true
If, however, you run the code in JsLint it says
Problem at line 12 character 5: Expected an identifier and instead saw 'delete' (a reserved word).
delete: function (name) {
Suggesting that this is a big no no approach and should be avoided.
So when should I take reserved keywords into consideration, as in this example it seems to work just like I want it to ( the delete keyword is in the context of the object cookieManager and thus causes no conflicts, hence it can be used ) or should I abide to the bible that is JsLint and rename anything that is a reserved keyword by javascript? In this context I could easily rename .delete() to .remove().
Actually this is allowed as per ECMAScript specification. The production rules (Section 11.1.5) for an object literal are:
ObjectLiteral :
{}
{PropertyNameAndValueList}
{PropertyNameAndValueList ,}
PropertyNameAndValueList :
PropertyAssignment
PropertyNameAndValueList , PropertyAssignment
PropertyAssignment :
PropertyName : AssignmentExpression
get PropertyName ( ){FunctionBody}
set PropertyName (PropertySetParameterList){FunctionBody}
PropertyName :
IdentifierName
StringLiteral
NumericLiteral
In your case, you use an IdentifierName as property name. Section 7.6.1 says:
A reserved word is an IdentifierName that cannot be used as an Identifier.
Note the difference: You cannot use a reserved keyword as Identifier, but as it is a valid IdentifierName you can use it as PropertyName.
Nevertheless, other (versions of) browsers might not tolerate this, so to be on the safe side, I would rename it.
Apart from possible problems with browsers, it might also confuse others who read your code and are not familiar with this rule.
FWIW, of course you can always use reserved keywords as strings:
var a = {'delete': 'foo'};
alert(a['delete']);

javascript JSON and Array elements, help me understand the rule about quotes

When using a returned value to determine the number of an element in an array, does javascript throw quotes around it?
Example :
This tallys the number of times unique characters are used.
var uniques = {};
function charFreq(s)
{
for(var i = 0; i < s.length; i++)
{
if(isNaN(uniques[s.charAt(i)])) uniques[s.charAt(i)] = 1;
else uniques[s.charAt(i)] = uniques[s.charAt(i)] + 1;
}
return uniques;
}
console.log(charFreq("ahasdsadhaeytyeyeyehahahdahsdhadhahhhhhhhhhha"));
It just seems funny that uniques[s.charAt(i)] works, and uniques[a] wont work (due to lack of quotes). uniques[a] will get you a nasty 'a is undefined'.
When you access a JavaScript object using the [] notation, you are using a string as a key in the object. You can also address properties using the . notation:
uniques.a is the same as uniques['a']
The reason you aren't adding quotes to the s.charAt(i) is that it returns a string, which is then used as the property to check on the uniques object.
uniques[a] will create an error, because no variable with the name a has been defined.
In the first version -- uniques[s.charAt(i)] -- you're doing the lookup using an expression. JavaScript evaluates the expression -- s.charAt(i) -- and uses the evaluated value (maybe a) to perform the lookup in the uniques map.
In the second version -- uniques[a] -- you want to do the lookup using the literal character a, but unless you wrap it in quotes then JavaScript treats the a as an expression rather than a literal. When it tries to evaluate the "expression" then you get an error.
So the rule is: character/string literals need quotes; expressions that evaluate to characters/strings don't.
This is how Javascript evaluates the expression between [] like uniques[s.charAt(i)] which is of the type MemberExpression[ Expression ] :
Let propertyNameReference be the result of evaluating Expression.
Let propertyNameValue be GetValue(propertyNameReference).
Let propertyNameString be ToString(propertyNameValue).
So in the 3rd step it is converting the property name into a string.

Categories

Resources