Understanding the Context of Curly Brackets '{}' - javascript

I have been reviewing other people's code and while ES2015 on the whole is taking some getting use to, however, I keep on getting stuck with Destructuring.
Previously, In Javascript, the Curly Brackets {} were either used for blocks or objects. e.g.
// Curly Brackets Block
If () {
...
}
// Curly Brackets in Obj
var obj = {
a : 1,
...
}
However, in destructuring, we see again and again the following syntax:
let a = ({ a, b }) => {
}
My question, is the arguments container an actual object or just a block?
Please explain whether the following be the same as the code above:
let a = ( a, b ) => {
}
EDIT: My understanding (so far) from reading Axel Rauschmayers article on Destruturing is that we are merely mapping the props. into a new Obj always? I.e:
let a = { first : a, second : b } = AnObj;
===
a.a === AnObj.first;
a.b === AnObj.second;
Is the above correct? Is an obj always instantiated? However, that doesn't make sense as in the above function, the object thus created for the props would be an anonymous object, right?
Many thanks,

No, the curly braces in destructuring do form neither a block nor an object literal.
They definitely are not a block because they are not a statement (and don't contain a statement list), they are an expression like an object literal. In fact they even do have the same syntax as an object literal, the only difference is that they are in the position of an assignment target (left hand side of an assignment operator) or a function parameter.
Is let a = ({ a, b }) => {…} the same as let a = ( a, b ) => {…}?
No, really not. Both parameter lists do declare variables a and b for the function scope, but the first function expects an object with properties .a and .b while the second function expects two arguments.
My understanding is that we are merely mapping the properties into a new obj?
No. There is no new object created/instantiated. There is only the object that you pass in (the right hand side). And it is destructured - "pulled apart" - into pieces that are then assigned to the various sub-targets (variables, property references).
To write
a.b = anObj.first;
a.c = anObj.second;
with a destructuring assignment you'd use
({first: a.b, second: a.c}) = anObj;
(the parenthesis are necessary to distinguish the expression from a block).
The more common use case is for variable initialisations however. You can shorten
let b = anObj.first,
c = anObj.second;
to
let {first: b, second: c} = anObj;
And also there's a shorthand when the variable has the same name as the property, so
let first = anObj.first,
second = anObj.second;
is equivalent to
let {first, second} = anObj;
Is let a = { first : a, second : b } = anObj; correct?
No, that doesn't make much sense. It would desugar to
let a;
a = anObj.first;
b = anObj.second;
a = anObj;

It is for destructuring:
var obj = {a: 1, b: 2},
add = ({a, b}) => a + b;
console.log(add(obj)); //3
So basically to the statements inside the function it would appear there are 2 arguments, but when you call it you only pass an object.

Related

Unlike Java, does an assignment operator in Javascript mean that all operations on the LHS are reflected for the RHS?

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

Object literal constructor

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])

What is this JavaScript construct called

I've found a JavaScript arrow function that looks something like this:
([a,b,c]) => {
a = 1;
b = 2;
c = 'x';
}
How is this function invoked? Also, what is this construct called?
This is an arrow function, which gets an array as a parameter and destruct the first 3 values into the corresponding parameters - a,b,c. But it must be assigned to a variable or be self invoked.
() => {} - Arrow function
[a,b,c] - Array destructuring
Example
const func = ([a,b,c]) => {
console.log(a);
console.log(b);
console.log(c);
};
func([1,2,3,4]);
([a, b, c]) => {}
The first part is a destructuring assignment in the parameters, which takes an array as parameter and returns the variables with the values of the position.
The later assignment makes no sense with the given code.

Confusion in destructuring in ES6

In the following JS (es6) code, what is going on with the variables inside of the curly braces with the colon?
const { foo: bar } = ...
Normally when you see this it is doing variable assignment from right to left, as in Objects. In objects it would assign the variable bar to the object key foo, but that doesn't seem to be what is going on here. What is this doing?
It is best to think of destructuring kind of like the opposite of declaring an object, so where
const hidingSpotConnection = ...
const obj = { connectionType: hidingSpotConnection };
would make an object obj with a key connectionType containing the value from the hidingSpotConnection variable,
const { connectionType: hidingSpotConnection } = ...
takes the value from the connectionType key and stores it in a variable called hidingSpotConnection.

Why is JavaScript passing by reference? [duplicate]

This question already has answers here:
Why isn't this object being passed by reference when assigning something else to it?
(4 answers)
Closed 9 years ago.
var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b[0] = 1;
alert(a[0] + ' ' + b[0]);
}
why();
The result is a[0]=1, b[0]=1;. It seem likes JavaScript is passing by reference?
But in this case:
var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b = [1, 2, 3];
alert(a + ' ' + b);
}
why();
The result is a=[3,4,5] and b = [1,2,3]. Why is it passing by value?
How to avoid passing by reference?
The value of a non primitive variable, in JavaScript like in most object languages, is a reference to the object.
In the second case, you're not changing the array, but the reference that is stored in b.
If you want to copy your array, use
var c = a.slice();
Then c and a will evolve independently.
Because that's how variables work.
In the first case, you're setting both variables to the same instance of one array, then modifying that array through b (b[0] = 1). You could also modify the same array through a, but the point is b and a point to the same array; b does not "point" to a.
In the second, you're setting both to the same instance of one array (b = a) but then setting b to an instance of an entirely new, different array (b = [1,2,3]). You're changing the array that b points to, you're not affecting a because, as I said, b didn't point to a, it pointed to the same value as a.
The variables b and a are pointing to an object. When you do b = // something, you're changing where the variable points to. You're not changing the underlaying object.
In the first code, b = a means that b and a are now pointing to the same object. Therefore, when you make a change to one, it's reflected in the other.
However, in the second example, you're first pointing b to the same object as a, but then pointing b to a new array ([1,2,3]). The fact it was pointing to a for a short amount of time is irrelevant.
Both cases are pass-by-value. JavaScript is always pass-by-value, there is no way to pass by reference. In particular, the value being passed is always a pointer to an object. (Actually, primitives are passed by value directly, but the difference can only be observed for mutable values and primitives are immutable, so it doesn't make a difference.)
In the first case you are mutating the object the pointer points to. But the reference doesn't get changed, only the object the reference points to. The reference still points to the same object, the object just looks different than it did before.
This specific case of pass-by-value-where-the-value-is-a-pointer is sometimes called call-by-object-sharing, call-by-object or call-by-sharing, and is the way argument passing works in pretty much all object-oriented languages: Smalltalk, Python, Ruby, Java, C# (by default, you can pass-by-reference by explicitly specifying the ref modifier) etc.
In first case are changing one value of array item. b now equals to a so a[0] and b[0] gives same value.
In second case even though you made b point to a, you assigned a new object to b. so again b and a are two different objects ...so different values.
After all these great Answers, there is not really more to say, so heres an explanation based on the ECMAScript 5 specification.
Also a deepclone function at the end of the Answer.
As defined in the ES5 specification,
11.13.1 Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
Let rval be GetValue(rref).
Throw a SyntaxError exception if the following conditions are all true:
Type(lref) is Reference is true
IsStrictReference(lref) is true
Type(GetBase(lref)) is Environment Record
GetReferencedName(lref) is either "eval" or "arguments"
Call PutValue(lref, rval).
Return rval.
So whats happening when we reach point 3 and rref is an Object, is
§8.7.1 (section 4b of In GetValue(V) //V==rref is the interesting point)
4.
If IsPropertyReference(V), then
(b) Return the result of calling the get internal method using base as its this value, and passing GetReferencedName(V) for the argument.
Now at this point rval holds the reference to the Object, which then gets put in at 5.
Where §8.7.2 (again 4b of PutValue(V,W) //V==lref , W==rval is the interesting part) comes into play.
Note: W is atm the reference to the Object you want to assign and not the value
4.
Else if IsPropertyReference(V), then
(b) Call the put internal method using base as its this value, and passing GetReferencedName(V) for the property name, W for the value, and IsStrictReference(V) for the Throw flag.
As you can see in your case the value of b which is atm a reference to the Object [6, 7, 8] gets replaced with the result of, so to speak GetValue(rref), which is a reference to [1, 2, 3];
However
Apparently you are looking for a deep clone function
Here is one.
Object.defineProperty(Object.prototype, "clone", {
value: function (deep) {
var type = Object.prototype.toString.call(this).match(/^\[object (.+?)\]$/)[1];
if (type !== "Object") {
return this.valueOf;
}
var clone = {};
if (!deep) {
for (var prp in this) {
clone[prp] = this[prp];
}
} else {
for (var prop in this) {
if (typeof this[prop] !== "undefined" && this[prop] !== null)
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone((typeof deep == "boolean" ? deep : (deep - 1))));
else
clone[prop] = "";
}
}
return clone;
},
enumerable: false
});
Object.defineProperty(Array.prototype, "clone", {
value: function (deep) {
var clone = [];
if (!deep) clone = this.concat();
else this.forEach(function (e) {
if (typeof e !== "undefined" && e !== null)
clone.push((typeof e !== "object" ? e : e.clone((deep - 1))));
else
clone.push("");
});
return clone;
},
enumerable: false
});
var a = [1, [2, { a: 3 } ], 4];
var b = a.clone(Infinity);
a[1][1]["a"] = "cloned";
console.log(a[1][1]["a"], b[1][1]["a"]); //"cloned" , 3
And a Demo on JSBin
To use it just call .clone(levelOfDeepness) on an Object or Array
Note: I used the Objects prototype for simplicities sake as i can call directly .clone of Object and Array elements while cloning them (gives a performance boost over the type checking variant in a single function)

Categories