I was reading javascript questions where i found this piece of code
var a={},
b={key:'b'},
c={key:'c'};
a[b] = 123;
a[c] = 456;
console.log(a[b]); // o/p - 456
can anybody make me understand this code why and how it is printing 456?
And I think we can use dot i.e a.b = 123 and string a['b'] = 123 approach to add property to an object.
Both b and c resolve to the same string ([object Object]). Hence you are overwriting the same key.
And I think we can use dot i.e a.b = 123 and string a['b'] = 123
approach to add property to an object.
Yes you can, but a['b'] is very different from a[b]. The first one resolves to a key with a string value just as it shows ('b'), where as the other one will depend on the stringified value of the variable b (in this case is [object Object]).
For really using the content of the object, you may use the stringified version.
var a = {},
b = { key: 'b' },
c = { key: 'c' };
a[JSON.stringify(b)] = 123;
a[JSON.stringify(c)] = 456;
console.log(a[JSON.stringify(b)]);
Related
MDN states here
JavaScript object property names (keys) can only be strings or
Symbols.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#object_initializers
However, it is stated here
Additionally, you can use a numeric or string literal for the name of a property or nest an object inside another.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#literals
These are seemingly conflicting statements. My question is,
What is MDN documentation actually saying here? Am I missing something?
What is allowed and what is not allowed as property names?
If object property names can only be strings then does that mean numbers get implicitly converted to strings.
The latter is not about keys per se but rather about what can be used as a key in object literals (so that the interpreter accepts a literal in your code) .
Take
var o = {};
var p = {};
o[p] = 1;
What key is used to store 1 in o? It's '[object Object]', as this is just p promoted to a string (p.toString())
On the other hand
var p = {};
var o = { p: 1, 7: 2 };
Despite p being an object, in the object literal { p: 1, 7: 2 }, p is just a string, the key name. The 7 is promoted to string and makes the second key. The two keys are then 'p' and '7'.
However if a key is enclosed in brackets
var p = {};
var o = { [p]: 1, 7: 2 };
its actual value is used, which means that now, o has two keys, '[object Object]' and '7'.
Edit Regaring the question about [object Object]. The default implementation of the .toString() for an empty object returns this exact string, [object Object].
var p = {}
console.log( p.toString() );
Thus, if an empty object is used as a key, the key name is [object Object]. Interestingly, overrding the toString() changes the key to the toString()'s value:
var o = {}
var p = {
toString: function() {
return 'foo bar';
}
}
console.log( p.toString() );
o[p] = 1;
console.log( Object.keys(o) );
In the above example, the indexing object toString() has been overridden to provide an alternate value (foo bar) and thus, using p as an index creates foo bar key in o (which is shown by calling Object.keys(o)).
Yes, number keys are converted to strings.
const obj = {2: "hello"}
const keys = Object.keys(obj)
console.log(keys)
console.log(typeof keys[0])
console.log(obj[2])
console.log(obj['2'])
// that's true for arrays too
const arr = ["world"]
console.log(Object.keys(arr))
console.log(arr["0"])
This is in continuation to the answer posted for the question "Convert JavaScript dot notation object to nested object".
The code works like a charm but I'm unable to wrap my head around how!! So a few days later + a situation where my console.logs actually exceed my lines of code :P.. Here's my question:
Below code for JavaScript function:
function deepen(o) {
var oo = {}, t, parts, part;
for (var k in o) {
t = oo;
parts = k.split('.');
var key = parts.pop();
while (parts.length) {
part = parts.shift();
t = t[part] = t[part] || {};
}
t[key] = o[k]
}
return oo;
}
console.log(
deepen({ 'ab.cd.e' : 'foo', 'ab.cd.f' : 'bar', 'ab.g' : 'foo2' })
);
It deepens a JSON object from :
{
'ab.cd.e' : 'foo',
'ab.cd.f' : 'bar',
'ab.g' : 'foo2' }
Into a nested object :
{ab: {cd: {e:'foo', f:'bar'}, g:'foo2'}}
I get the part where for each key value pair, the logic pops the last element post splitting into an array by ".".
That becomes the key.
What I'm not understanding is the below.
1) The function is returning 'oo' but the operations are all on 't'. The only relationship is that t is being assigned the'empty object' "oo" at the beginning of every iteration on the flat JSON.
2) after the "while (parts.length)" loop, oo miraculously has the nested structure whereas t has one level below it. if oo is assigned to t, how is that possible?
3) I don't see the function being called recursively. How is 00 getting nested beyond the first element of the flat JSON?
I'll first redefine the function with some better names, this way explanation is a lot easier to do.
function deepen(object) {
var nestedObject = {}, cursor, nestingPath, nodeKey;
for (var dotKey in object) {
cursor = nestedObject;
nestingPath = dotKey.split('.');
var leafKey = nestingPath.pop();
while (nestingPath.length) {
nodeKey = nestingPath.shift();
cursor = cursor[nodeKey] = cursor[nodeKey] || {};
}
cursor[leafKey] = object[dotKey];
}
return nestedObject;
}
My guess is that don't entirely know how the while loop functions. Important to know is that when two variables refer to the same object both change when you change one. They are the same object, but you've chosen to have two handles.
Let me provide an example:
object = {};
cursor = object;
cursor.foo = "bar";
object; //=> {foo: "bar"}
cursor; //=> {foo: "bar"}
cursor.a = {};
object; //=> {foo: "bar", a: {}}
cursor; //=> {foo: "bar", a: {}}
cursor = cursor.a;
object; //=> {foo: "bar", a: {}}
cursor; //=> {} <- this is ^
cursor.b = "c";
object; //=> {foo: "bar", a: {b: "c"}}
cursor; //=> {b: "c"}
The while loop is mostly based upon this principal. It's not easy to explain, but I hope the above clarifies things.
Another thing that might be confusing is the line:
cursor = cursor[nodeKey] = cursor[nodeKey] || {};
// read as
cursor = (cursor[nodeKey] = (cursor[nodeKey] || {}));
This could also be written as:
if (!cursor[nodeKey]) cursor[nodeKey] = {};
cursor = cursor[nodeKey];
This assigns a new object to the dynamic nodeKey property if the property isn't there (falsy). Then cursor is assigned to the nested object within, similar to my example above cursor = cursor.a.
First, you're not working with JSON, but a JS object. Most of the time, you should see object as HashMap<String, HashMap<String, ...>> ad infinitum, if you need a Java analogy.
Your questions:
t = oo means they both refer to the same instance created at the start of the function. Why do you use a second variable?
t = t[part] You literally assign entry of t to t
I didn't test the code, but I'm pretty sure it's buggy. Test what happens with object that have multiple names in top level, eg. {'a.b':1, 'b.a':1}. You don't need recursion though, you could use stack instead.
Regarding your code:
Use descriptive names and comments, especially when asking question where other people need to understand your code
Do not define all variables at the beginning of the function. That old habit comes from the dawn of C language and needs to die
for (var k in o) is not a recommended approach to iterate over object entries. Use Object.entries
There is no need to pop from parts array, it is reset every iteration. for(const part of parts) would work just as well
I am looking for a way to modify an object that was defined by a literal without passing it into another function.
example:
let o = {a:1,b:2}
console.log(o.a===3)
i thought when i define an object using a literal the the Object constructor would be called, so i did override Object.prototype.constructor but it only gets called when i do new Object({a:1,b:2})
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy or using o.a=3 or with keyword, where o is defined using an object literal?
Just do o.a=3; and console log o:
let o = {a:1,b:2};
o.a=3;
console.log(o);
Currently you are doing o.a===3 which will return Boolean value instead of overwriting the value of property a.
You also cannot do o.a=3 inside console.log() because o.a=3 will return the assigned value which is 3 but it will still change the property a of o to 3.
let o = {
a: 1,
b: 2
};
//won't print o but changes o.a to 3
console.log(o.a = 3);
It's simply not possible.
There is no constructor of an object literal.
You can create objects in different ways:
via an object literal or
via a constructor function or
via Object.create
Also, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy?
o.a = 3;
I am looking for a way to modify an object that was defined by a literal without passing it into another function.
Thats impossible, cause if it would be possible you could break every piece of javascript. And that would be terrible.
Oh wait, this is JS...
with({ get o() { return { a: 3 }; }, set o(v) {} }) {
o = {a:1,b:2};
console.log(o.a===3) // true
}
What you want to achieve could be done if o.a holds a reference to the variable a - which unfortunately only works the way you'd like for variables that are passed by reference. Primitive types like String, Number and Boolean though, are passed by value.
Check the examples below:
var a = 1;
var o = { a: a };
a = 2;
console.log(o.a, a);
It also doesn't help to use an Object constructor like new Number() because that does return a reference to an object (which is passed by reference as you'd need), but assigning a new value to it reading the value still returns a primitive (which is, again, passed by value):
var a = new Number(1);
var o = { a: a.valueOf() };
a = Number(2);
console.log(o.a, a);
If you pass something that is naturally passed by reference, your expectation is fulfilled:
var a = [ 1 ]
var o = { a: a }
a[0] = 2
console.log(o.a[0])
I need helps with convert the statement below to ES5 syntax. What will it be in ES5?
const { a, b, c = “foo” } = this.props;
I suggest to use an explicit check if property c exists in the given object or not. If not given, then use the default value.
var a = this.props.a,
b = this.props.b,
c = this.props.c === undefined ? 'foo' : this.props.c;
The otherwise used pattern
c = this.props.c || 'foo';
does not work for given falsy value like zero.
Why do you need a check with undefined (kudos to loganfsmyth for mention this problem in comments)?
Because undefined is the value for the check for default parameters in a function in ES6.
const f = (c = 'foo') => console.log(c);
f(); // 'foo'
f(undefined); // 'foo'
f(0) // 0
var
a=this.props.a,
b=this.props.b,
c=this.props.c||"foo";
Object destructuring trys to find properties with the same name in the object, so
{prop}=obj
equals:
prop=obj.prop;
The default parameter can be easily achieved with an Or operator:
prop=obj.prop || default;
or if you want to count falsys as a prop, itll be:
prop=("prop" in obj)?obj["prop"]:default;
I believe it would be :
var a = this.props.a,
b = this.props.b,
c = this.props.c || "foo"
At least I hope, otherwise it'll be raining downvotes
The easiest way to achieve this would be:
var a = this.props.a,
b = this.props.b,
c = this.props.c===undefined?"foo":this.props.c
But the better way would be to just use the this.props object instead of storing it in local variables.
This question already has answers here:
Add a property to a JavaScript object using a variable as the name? [duplicate]
(14 answers)
Closed 7 years ago.
I want to add a new property to 'myObj', name it 'string1' and give it a value of 'string2', but when I do it it returns 'undefined:
var myObj = new Object;
var a = 'string1';
var b = 'string2';
myObj.a = b;
alert(myObj.string1); //Returns 'undefined'
alert(myObj.a); //Returns 'string2'
In other words: How do I create an object property and give it the name stored in the variable, but not the name of the variable itself?
There's the dot notation and the bracket notation
myObj[a] = b;
ES6 introduces computed property names, which allow you to do
var myObj = {[a]: b};
Dot notation and the properties are equivalent. So you would accomplish like so:
// const myObj = new Object();
const myObj = {};
const a = 'string1';
myObj[a] = 'whatever';
alert(myObj.string1);
(alerts "whatever")
Ecu, if you do myObj.a, then it looks for the property named a of myObj.
If you do myObj[a] =b then it looks for the a.valueOf() property of myObj.
Oneliner:
obj = (function(attr, val){ var a = {}; a[attr]=val; return a; })('hash', 5);
Or:
attr = 'hash';
val = 5;
var obj = (obj={}, obj[attr]=val, obj);
Anything shorter?
You could just use this:
function createObject(propName, propValue){
this[propName] = propValue;
}
var myObj1 = new createObject('string1','string2');
Anything you pass as the first parameter will be the property name, and the second parameter is the property value.
You cannot use a variable to access a property via dot notation, instead use the array notation.
var obj= {
'name' : 'jroi'
};
var a = 'name';
alert(obj.a); //will not work
alert(obj[a]); //should work and alert jroi'
As $scope is an object, you can try with JavaScript by:
$scope['something'] = 'hey'
It is equal to:
$scope.something = 'hey'
I created a fiddle to test.
The following demonstrates an alternative approach for returning a key pair object using the form of (a, b). The first example uses the string 'key' as the property name, and 'val' as the value.
Example #1:
(function(o,a,b){return o[a]=b,o})({},'key','val');
Example: #2:
var obj = { foo: 'bar' };
(function(o,a,b){return o[a]=b,o})(obj,'key','val');
As shown in the second example, this can modify existing objects, too (if property is already defined in the object, value will be overwritten).
Result #1: { key: 'val' }
Result #2: { foo: 'bar', key: 'val' }