Why does Javascript syntax not support inline object literals with a variable property? For example:
const f = function (arg) {
console.log(arg);
}
f({}['some key'] = 1) // 1
f({ 'some key' : 1}) // [object Object] { some key: 1 }
Is there another alternative other than the two steps?
var o = {}
o['some key'] = 1
f(o)
Thanks!
Why does Javascript syntax not support inline object literals with a variable property?
You seem to be asking about variable properties, yet your examples do not use variables. Specifically, this example will work just fine.
f({ 'some key' : 1})
However, if you actually did want to use a variable without first creating the object, ECMAScript 6 now allows this.
So if this is your variable:
var my_variable = 'some key';
You can now use square brackets around the property name in the object literal, and it will use the value of the expression you provide:
var o = {[my_variable]: 1};
The o object will have a property named "some key". This only works in the implementations that support this syntax of course.
Related
Sometimes I find myself needing to initialize an object with a property that matches the property of another object. When the property name is the same, I want to be able to use shorthand syntax.
(For the purposes of the examples in this question, I'll just keep the additional properties to a tag: 1 property, and I'll reuse message in subsequent examples as the input/source of the information. I also indicate an extra unwanted property of message because I'm cherry-picking properties and do not intend to just use Object.assign to assign all the properties of message to the result.)
const message = {
person: {
name: 'John'
},
unwanted: 'x'
};
let result = { person: message.person, tag: 1 }; // Looking for shorthand for this
To formulate the result object above, I needed to type person twice. I was thinking there must be a shorthand way to do this. My reasoning for expecting this to work is that features exist like ES2015 Shorthand property names and Destructuring assignment. e.g:
const { person } = message; // destructing assignment
let result = { person, tag: 1 }; // shorthand property name for `person`
This would create an extra variable called person that has the value of message.person, And the result would have a property called person that has the desired value. But if there's no variable already existing then I don't know how to use shorthand in this case. And I haven't found a way to apply these two syntactical features together.
This was my first intuitive guess at what the syntax would be:
// hoping destructuring assignment is allowed in object literal
let result = { {person} = message, tag: 1 }; // it is not legal :(
My second guess was this:
// hoping that a property name would magically be inferred from `person`
let result = { message.person, tag: 1 }; // it is not legal :(
As a last resort I tried Object.assign, but it copies unwanted properties and does not cherry-pick just the person property of message.
let result = Object.assign({ tag: 1 }, message); // Assigns unwanted properties :(
So the best I have so far is { person: message.person, tag: 1 }
Is there shorthand initializer syntax to achieve this?
The best I have so far is { person: message.person, tag: 1 }.
Is there shorthand initializer syntax to achieve this?
No, this is still they way to go.
hoping that a property name would magically be inferred from person
let result = { message.person, tag: 1 };
There is the ECMAScript Shorthand Property Assignment Improvements proposal that would allow exactly this. Unfortunately, it's still at stage 0 :-/
Assuming you're using ES6:
const message = {
person: {
name: 'John'
},
unwanted: 'x'
};
let { unwanted, ...result } = { ...message, tag: 1 };
console.log(result);
If you'd like to rename the unwanted variable to something then to dit
let { unwanted: dummy, ...result } = { ...message, tag: 1 };
These have some issues, e.g
This creates an extra variable unwanted (or dummy if you use the 2nd approach)
If you have multiple unwanted properties, you have to write them all in the destructuring
So in my opinion, you're better off to go with the way you described in your question already.
What is wrong with alert({s[prop]}) but fine with this placeholder={s[prop]}
It says I am missing a ',' after 's' and ':' after ']'
In React, the { }s around attributes are essentially expression delimiters - they indicate that what follows between the brackets is an expression. So, if you have const str = 'foobar', then:
placeholder={str}
evaluates to
placeholder='foobar'
But, in alert, you're not writing JSX - you're writing plain JS. When in an expression context, { indicates the start of an object literal. But the following is not a valid object literal:
const obj = {
s[prop]
}
because objects require keys and values (usually). Perhaps you wanted to do
alert(s[prop])
The only time an object literal doesn't require a value is when you're using the shorthand syntax, when you have a variable in the current scope and want to define an object with a property with the same name as the variable, and the same value as a variable, eg:
const str = 'foobar';
const obj = { str };
This results in an object like { str: 'foobar' }.
In any other situation, you'll need to define the property name in addition to the value, eg
{ somePropertyName: s[prop] }
alert(s['use your key'])
Please use in this way. Avoid using {} in alert(), If you use you will see [object Object] instead of actual dynamic content.
try with
alert(s[prop])
In JSX to print any JS variable it must be wrap inside curly braces, but not required when using in JS, alert is the JavaScript function.
Defining a utility function to inspect objects' prototype chains (in Chrome), I get this for arrays.
So it would appear that
[].__proto__ === Array.prototype // === [Symbol(Symbol.unscopables): Object]
I understand the first equality. I have no idea what the third term is, though I have heard that ES6 will have Symbols.
Is this thing the same as Array.prototype? Why does it print that way?
Edit: chrome://version information:
Google Chrome 40.0.2214.111 (Official Build)
Revision 6f7d3278c39ba2de437c55ae7e380c6b3641e94e-refs/branch-heads/2214#{#480}
OS Linux
Blink 537.36 (#189455)
JavaScript V8 3.30.33.16
Comment on 2014-04-14
It seems Chrome's console.log print all Symbol-type-keys, here is an example:
var o = {};
o[Symbol.iterator] = function () {};
o[Symbol.unscopables] = {};
var s = Symbol('s');
o[s] = 3;
console.log(o);
which prints:
Object {Symbol(Symbol.unscopables): Object, Symbol(Symbol.iterator): function, Symbol(s): 3}
I don't why chrome behaves this way, is it for debugging or something else?
Fotunately it does not affect the toString() result so all code is safe.
It seems console.log would especially print the Symbol.unscopable key in console, we can have a plain object to perform like this:
var o = {};
o[Symbol.unscopables] = {};
console.log(o);
which outputs:
Object {Symbol(Symbol.unscopables): Object}
The Symbol.unscopables symbol is a special symbol defined in ES6 as ##unscopables which is used for excluding some properties when this object works in a with environment, the official explanation is:
An object valued property whose own property names are property names that are excluded from the with environment bindings of the associated object.
A simple example:
var o = {x: 1, y: 2};
o[Symbol.unscopables] = {
y: true
};
console.log(o.x); // 1
console.log(o.y); // 2
with(o) {
console.log(x); // 1
console.log(y); // ReferenceError: y is not defined
}
You can use Array.prototype[Symbol.unscopables] to find all keys which cannot be used in with environment
However still, the output of a Array.prototype is not exactly the same as a plain object with Symbol.unscopables key, it outputs [Symbol(Symbol.unscopables): Object], which is a format more like an array
I can't exactly explain why, this may be related to the Symbol.toStringTag which controls how an object should be formatted to string, but Chrome currently does not export this symbol so it's hard to test
Imagine this object:
var obj = {
one: {
two:{
three: "whatever"
}
}
}
If I want to access "whatever" I simply do:
console.log( obj.one.two.three ) --> "whatever"
And I can even use a variable like:
var one = "one"
console.log( obj[one].two.three ) --> "whatever"
But why doesn't this work ?
var onetwo = "one.two"
console.log( obj[onetwo].three ) --> undefined
But why doesn't this work ?
Because the notation is not supported in the language. It's simply not there. The specification defines property access as with bracket notation as:
MemberExpression [ Expression ]
The algorithm for defining how that works is defined in the lines below, the syntax for nested properties is simply not a part of the core language syntax.
There are specific parsers that let you do this, and you can always invoke the language compiler yourself (JS lets you do that with eval for example - don't though), but the use case is not common enough.
Note:
Since you mentioned in the comments you use Angular, it already has that built in using $parse doing var res = $parse("one.two.three")(obj); Here's a fiddle.
This question already has answers here:
JavaScript property access: dot notation vs. brackets?
(17 answers)
Closed 9 years ago.
What is the difference, if any, between these two assignments:
var foo = {};
foo['bar'] = "some value";
foo.baz = "some other value";
console.log(foo.bar)
=> "some value"
console.log(foo.baz)
=> "some other value"
Are they synonymous? I've noticed you can add keys with the [] syntax that are not valid property names.
foo['a space'] = "does not work";
console.log(foo.a space);
=> SyntaxError: Unexpected identifier
My reason for asking is that I've cooked up a little JS library for pseudo namespacing. It is written on the assumption that the above assignments are identical (ignoring the superset allowed when using [] syntax)
foo["bar"] is equivalent to foo.bar, although foo.bar is easier to read in my opinion. As you already noticed the former syntax (foo["bar"]) allows you to use property names that are not valid identifiers. It also allows you to use dynamic property names:
var name = "bar";
foo[name] = 1;
console.log(foo["bar"]);
will output 1.
When you use ., the property name is a literal identifier. When you use this in a program, you have to hard-code the property name.
When you use [], the property name is an expression that is evaluated. It's not normally used with simple strings in quotes, because that's what . notation is for. But it's useful when you need to calculate the property, e.g.
console.log(foo["item"+i]);
This latter notation is also the only way to access properties that aren't identifiers. You can use any string as the property name this way.
They are absolutely equivalents except that you can more possibilities with [] syntax for example
var bar = 'text';
foo[bar] = 'baz';
The only difference is you can use variables in the second example however it's is always better to use dot notation like this
someObject.hello = ' hello john';
And the only time i use the other way is if i need to use a variable like this
var msg = 'goodbye';
someObject[msg] = 'goodbye john';
This would be the result
// someObject.hello => 'hello john'
// someObject.goodbye => 'goodbye john'
so use dot notation like obj.some and use obj[myVar] for variables
So the difference is you can use variables in the 2nd example
also if i done this
var myVar = 'test';
someObj.myVar = ' Hello Test ';
then this would be the result
// someObj.test => doesnt work - undefined
// someObj.myVar => ' Hello Test '
They are equivalent, but you cannot use the dot notation when the attribute-name contains a space (or other non-alphanumeric characters):
foo.a space // doesn't work
foo['a space'] // does