Imagine the following array of objects representing individual people.
let people = [
{
name: 'Alice',
age: 19
},
{
name: 'Bob',
age: 32
},
]
You are asked to loop over each object and to add the person's hair and eye color to their object. Fortunately, your task is simplified by the fact that they both have brown hair and hazel eyes. For some reason, you decide to use a property accessor for Alice and a destructuring assignment for Bob. Finally, you log the result.
for (let i = 0; i < people.length; i++) {
let person = people[i];
if (person.name === 'Alice') {
person.hair = 'brown';
person.eyes = 'hazel';
}
else if (person.name === 'Bob') {
let additionalInfo = {
hair: 'brown',
eye: 'hazel'
}
person = { ...person, ...additionalInfo }
}
}
people.forEach(person => console.log(person));
However, the new information is present in Alice's object but not in Bob's!
{ name: 'Alice', age: 19, hair: 'brown', eyes: 'hazel' }
{ name: 'Bob', age: 32 }
Now, I understand why Alice's object gets updated: person.hair = 'brown' get treated as people[i].hair = 'brown' because person === people[i].
I somewhat but not fully understand why this doesn't work with Bob in this example. On one hand, we are reassigning the person variable to something other than people[i], thereby losing the reference, and person is lost after that iteration with no changes made to Bob's object.
On the other hand, my initial expectation was that changes to person would result in changes to people[i] because person === people[i]. Hence it is a little surprising the fix here is to swap out person = { ...person, ...additionalInfo } with people[i] = { ...person, ...additionalInfo }.
Why is this the case? Is it even possible to create a "stable reference" to an object in JS such that changes to the variable containing the reference are applied to the object it is referring to?
no,
person and people[i] are two reference to same thing..
when you assign to a reference it updates what it is pointing to
eg.
let a = {x:1}
if you do
b = a
b is not the object {x:1} .. it merely points to that object
when you do b.x = 3 . that works because you say change the x property on the object b is pointing to
but when you do
b = {y:2}
now you are saying b should point to this new object.. a still points to the older object and nothing changes there.
On the other hand, my initial expectation was that changes to person would result in changes to people[i] because person === people[i].
That's true for changes to what person/people[i] point to (the object), but not true for person the variable. The value in a variable (or property) that makes that variable refer to an object is called an object reference. When you assign to person, you're changing what's in the person variable (in your case, so that it points to a different object entirely).
You start out with something like this in memory (the "Ref12345" values are just for clarity, the numbers don't mean anything):
+−−−−−−−−−−−−−−−+
+−−>| (object) |
| +−−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−+ | | name: "Alice" |
people−−−>| (array) | | | age: 19 |
+−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−+
| 0: Ref13521 |−−+
| 1: Ref24612 |−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−+ |
v
+−−−−−−−−−−−−−−−+
person: Ref24612−−−−−−−−−−−−−−>| (object) |
+−−−−−−−−−−−−−−−+
| name: "Bob" |
| age: 32 |
+−−−−−−−−−−−−−−−+
but then when you do person = ___, you change the value of person (which object person points to), making it point to a whole different object that people[i] doesn't point to:
+−−−−−−−−−−−−−−−+
+−−>| (object) |
| +−−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−+ | | name: "Alice" |
people−−−>| (array) | | | age: 19 |
+−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−+
| 0: Ref13521 |−−+
| 1: Ref24612 |−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−+ |
v
+−−−−−−−−−−−−−−−+
| (object) |
+−−−−−−−−−−−−−−−+
| name: "Bob" |
| age: 32 |
+−−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−−+
person: Ref74324−−−−−−−−−−−−−−>| (object) |
+−−−−−−−−−−−−−−−+
| name: "Bob" |
| age: 32 |
| hair: "brown" |
| eyes: "hazel" |
+−−−−−−−−−−−−−−−+
Is it even possible to create a "stable reference" to an object in JS...
Object references in JavaScript are stable. This is just how variables work. (Not only in JavaScript, but also in many other languages with object references, such as Java, C#, PHP, ...) You could use a const for person instead of let: let person = people[i]; That would prevent you changing the value in person, so you couldn't point it at a different object. That would let you do the changes you did for Alice (modifying the object) but not Bob (creating a new object and having person point to it).
Related
I have the following simplified code:
var obj = {
key1 : {
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
}
var objHashMap = {};
for(var key in obj){
objHashMap[key] = obj[key];
objHashMap[obj[key].aliases[0]] = obj[key];
objHashMap[obj[key].aliases[1]] = obj[key];
}
Now objHashMap has 3 entries, and all entries points at:
{
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
My question is weather all 3 points to the same object, or points to 3 different copies of the object?
objHashMap.key1 will have a copy of the value in obj.key. That value is a reference to an object. Both copies of that value refer to the same object. The you use the value of obj.key1.aliases[0] and obj.key1.aliases[1] to create two additional properties which also have copies of the reference, referring to the same object.
After this:
var obj = {
key1 : {
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
}
...we have this in memory:
+----------------+
obj: ref-1654-->| (object) |
+----------------+ +-------------------+
| key1: ref-8754 |---->| (object) |
+----------------+ +-------------------+ +-------------+
| aliases: ref-6549 |---->| (array) |
| prop1: ??? | +-------------+
| prop2: ??? | | 0: "alias1" |
+-------------------+ | 1: "alias2" |
+-------------+
That is, we have a variable, obj, which contains a value that tells the JavaScript engine where an object is elsewhere in memory; I've shown that as ref-1654 above. Think of an object reference as a number that has meaning only to the JavaScript engine, like an index into a big array of memory. (The actual value of an object reference is something we never see.)
That object has a property, key1, which again has a value pointing to an object elsewhere in memory. That object, in turn, has aliases with another reference to an object (this time an array) in memory. The values of prop1 and prop2 in the object with aliases are unknown (they come from the variables someVal and someOtherVal, which you haven't defined for us).
Then this line adds another variable pointing to another object:
var objHashMap = {};
+----------------+
objHashMap: ref-8132-->| (object) |
+----------------+
| |
+----------------+
Your for-in loop only runs once, for the key "key1". After the first line:
objHashMap[key] = obj[key];
we have:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |---------+
+----------------+ |
|
|
| +-------------------+
+-->| (object) |
| +-------------------+ +-------------+
| | aliases: ref-6549 |---->| (array) |
+----------------+ | | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | | | prop2: ??? | | 0: "alias1" |
+----------------+ | +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+ +-------------+
+----------------+
Note how the key1 property in the new object contains the same value as the key1 property in the original object. They point to the same object.
Then you do:
objHashMap[obj[key].aliases[0]] = obj[key];
...which is to say
objHashMap[obj.key1.aliases[0]] = obj[key];
...since key contains "key1", which is to say
objHashMap["alias1"] = obj[key];
...because obj.key1.aliases[0] is "alias1". That gives us:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |-----------+
+----------------+ |
|
|
| +-------------------+
++-->| (object) |
|| +-------------------+ +-------------+
|| | aliases: ref-6549 |---->| (array) |
+------------------+ || | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | || | prop2: ??? | | 0: "alias1" |
+------------------+ || +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+| +-------------+
| alias1: ref-8754 |---+
+------------------+
Then again for this line:
objHashMap[obj[key].aliases[1]] = obj[key];
...which is:
objHashMap["alias2"] = obj[key];
...because obj.key1.aliases[1] is "alias2". So we end up with:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |-----------+
+----------------+ |
|
|
| +-------------------+
+++->| (object) |
||| +-------------------+ +-------------+
||| | aliases: ref-6549 |---->| (array) |
+------------------+ ||| | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | ||| | prop2: ??? | | 0: "alias1" |
+------------------+ ||| +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+|| +-------------+
| alias1: ref-8754 |---+|
| alias2: ref-8754 |----+
+------------------+
Yes, these point to the same object. Let me take an example to demonstrate the same:
var obj = {
key1 : {
aliases: [1,2],
prop1: 3,
prop2: 4
}
}
//initialize another object which will contain the same values.
var objHashMap = {};
for(var key in obj){
objHashMap[key] = obj[key];
objHashMap[obj[key].aliases[0]] = obj[key];
objHashMap[obj[key].aliases[1]] = obj[key];
}
//change the value of a key in objHashMap.
objHashMap["key1"].prop1 = 600
//now observe the value changed in other keys as well.
console.log(objHashMap[1].prop1);
console.log(objHashMap[2].prop1);
console.log(obj);
So you have a couple strongly typed Maps and you're building a UI that makes use of them by iterating, but you could be iterating over one or the other depending on another variable. TypeScript complains about the type "never" in an odd situation. (in fact TypeScript seems to have poor support for maps in general).
Consider this simplified example:
let isFirstPicked = false;
const testMap = !isFirstPicked ? MMeasurementType : MMeasurementSize;
const items = [...testMap.keys()].map(
key => key: ${key}, name: ${testMap.get(key).displayName}`
);
console.log(names);
This works just fine, but TypeScript complains about
testMap.get(key)
Argument of type '"T_SHIRT" | "DRESS" | "JACKET" | "PANTS" | "SHOES" | "XS" | "S" | "M" | "L" | "XL" | "XXL"' is not assignable to parameter of type 'never'.
Type '"T_SHIRT"' is not assignable to type 'never'.ts(2345)
I do not like using "any" but this makes the error go away:
(testMap as any).get(key)
Here are my typings:
export interface IDisplayName {
displayName: string;
}
export type TMeasurementType =
| "T_SHIRT"
| "DRESS"
| "JACKET"
| "PANTS"
| "SHOES";
export const MMeasurementType = new Map<TMeasurementType, IDisplayName>([
["T_SHIRT", { displayName: "T-Shirts" }],
["DRESS", { displayName: "Dresses" }],
["JACKET", { displayName: "Jackets" }],
["PANTS", { displayName: "Pants" }],
["SHOES", { displayName: "Shoes" }],
]);
export type TMeasurementSize = "XS" | "S" | "M" | "L" | "XL" | "XXL";
export const MMeasurementSize = new Map<TMeasurementSize, IDisplayName>([
["XS", { displayName: "XS" }],
["S", { displayName: "Small" }],
["M", { displayName: "Medium" }],
["L", { displayName: "Large" }],
["XL", { displayName: "XL" }],
["XXL", { displayName: "Double XL" }],
]);
To answer the "why" question, consider the following
interface Phone {
turnOn()
turnOff()
ring()
}
interface Printer {
turnOn()
turnOff()
print()
}
Let's add a new type, which is either a Phone or a Printer:
type Device = Phone | Printer
Mathematically, it's a Union of the set of phones and the set of printers. That's why it's called "union type". Now, given a Device object, what do we know for sure? Can it be turned on or off? Sure, because both the Phone and the Printer can do that. But can it print? The answer is generally no, because it might just happen to be a Phone, which can't. Can it ring? Similarly, the answer is no, because it can be a Printer. That is, the Device type only has methods that are common to Phone and Printer. That gives us the
fun fact #1: a union of compound types contains an intersection of their parts.
Now consider:
type FaxMachine = Phone & Printer
This is an "intersection type" and represents an object which is a Phone and a Printer at the same time. Can it be turned on/off? Sure. Can it ring? The answer is yes, because it is a Phone. Can it print? Again, yes, because it is a Printer. So,
fun fact #2: an intersection of compound types contains a union of their parts.
Back to the Maps example,
type keyA = 'x' | 'y' | 'a'
type keyB = 'x' | 'y' | 'b'
type A = Map<keyA, any>
type B = Map<keyB, any>
type U = A | B
What is the type of the keys of U? According to the above, it's keyA & keyB, that is, 'x' | 'y'. If the maps have disjoint sets of keys, as in
type keyA = 'a1' | 'a2'
type keyB = 'b1' | 'b2'
then the type of the keys of U will be an empty set, or never.
In your code, the type of
!isFirstPicked ? MMeasurementType : MMeasurementSize
is inferred as
Map<TMeasurementSize, IDisplayName> | Map<TMeasurementType, IDisplayName>
respectively, the keys have type
TMeasurementSize & TMeasurementType
which is never since there's no intersection.
Docs: https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types
As it turns out I was just under-utilizing the power of Maps, treating them more like dictionaries. Here is better code that also avoids the error:
let isFirstPicked = false;
const testMap = !isFirstPicked ? MMeasurementType : MMeasurementSize;
const items = [...testMap.entries()].map(
([key, value]) => `key: ${key}, name: ${value.displayName}`
);
console.log(items);
A very strange issue in my ExpressJS app.
My code:
console.log(req.user); // { user_id: '12345', name: 'Mr Example' }
var set = {};
set = req.user;
set['test'] = "testing";
console.log(req.user); // { user_id: '12345', name: 'Mr Example', test: 'testing' }
console.log(set); // { user_id: '12345', name: 'Mr Example', test: 'testing' }
Why does console.log(req.user) output the test property and value too? It seems to be copying whatever I do with the set variable. Why is this?
This is totally normal... if you set = <obj> it only adds reference to that object, not creating new one.
Just change:
set = req.user;
to:
set = Object.create(req.user);
Please note that it won't rewrite old values, you have to do it yourself...
for (var k in req.user) { set[k] = req.user[k]; }
JSFiddle
Or shorter version:
var set = Object.assign({}, req.user);
This one will copy all values.
JSfiddle
This line:
set = req.user;
makes set refer to the same object that req.user refers to (throwing away the reference it used to have to the object created in the previous line). From that point forward, they're both just ways to get at the same object in memory. So naturally, any change you make to that object by accessing it through one variable is also visible through the other, as they're both just referring to a single object.
Remember that the value in a variable or property that refers to an object isn't the actual object, it's a value called an object reference that tells the JavaScript engine where the object is elsewhere in memory. The same object can have lots of different variables and properties referring to it.
Let's throw some ASCII-art (well, Unicode-art) at it:
After the var set = {} line, you have this in memory (leaving out some details):
+−−−−−−−−−−+
req−−−−−>| (object) |
+−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+
| user |−−−−>| (object) |
+−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+
| user_id: "12345" |
+−−−−−−−−−−+ | name: "Mr Example" |
set−−−−−>| (object) | +−−−−−−−−−−−−−−−−−−−−+
+−−−−−−−−−−+
But then you do set = req.user, and so you have this:
+−−−−−−−−−−+
req−−−−−>| (object) |
+−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+
| user |−−+−>| (object) |
+−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−−−+
| | user_id: "12345" |
set−−−−−−−−−−−−−−−−−−−−+ | name: "Mr Example" |
+−−−−−−−−−−−−−−−−−−−−+
...and the object that set used to refer to doesn't have anything referring to it anymore, so it can be garbage-collected.
So of course, set['test'] = "testing" does this:
+−−−−−−−−−−+
req−−−−−>| (object) |
+−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+
| user |−−+−>| (object) |
+−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−−−+
| | user_id: "12345" |
set−−−−−−−−−−−−−−−−−−−−+ | name: "Mr Example" |
| test: "Testing" |
+−−−−−−−−−−−−−−−−−−−−+
Because objects in javascript are assigned by reference.
This means that when you write
set = req.user;
You are saying "I want the set variable and the req.user variable to reference exactly the same object."
So if both set and req.user are pointing to the very same object, changing the value on one will change the value on the other.
When you console.log both req.user and set you are logging exactly the same object twice.
set is a key word in javascript which it create new reference to existing object.. if you want to copy variable use some other variable reference instead of set.
console.log(req.user);
var userData = {};
userData = req.user;
userData['test'] = "testing";
console.log(req.user);
console.log(userData);
In the code below, does aObj remain in memory after garbage collection? And what is the easiest way I can test and see this?
var a = function(arg) {
this.argument = arg;
}
var aObj = new a({ prop1: 1, prop2: 2 });
var b = aObj.argument;
aObj = null;
No, it does not. After the aObj = null line, there are no remaining references to the object it used to contain. It has a reference to argument, but argument doesn't have a reference to it, and so after you've released the only reference to the object (in aObj), the object is eligible for garbage collection.
Let's stop the world just before the aObj = null line and see what's in memory (leaving out some details):
+−−−−−−−−−−−−−−−+
a−−−−−−−−>| (function) |
+−−−−−−−−−−−−−−−+
| (...) | +−−−−−−−−−−+
| prototype |−−−−+−−>| (object) |
+−−−−−−−−−−−−−−−+ | +−−−−−−−−−−+
| | (...) |
| +−−−−−−−−−−+
|
+−−−−−−−−−−−−−−−+ |
+−−>| (object) | |
| +−−−−−−−−−−−−−−−+ |
| | [[Prototype]] |−−−−+ +−−−−−−−−−−+
| | argument |−−−−+−−>| (object) |
| +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−+
| | | prop1: 1 |
aObj−−+ | | prop2: 2 |
| +−−−−−−−−−−+
b−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
Now, we do the aObj = null line, and get:
+−−−−−−−−−−−−−−−+
a−−−−−−−−>| (function) |
+−−−−−−−−−−−−−−−+
| (...) | +−−−−−−−−−−+
| prototype |−−−−+−−>| (object) |
+−−−−−−−−−−−−−−−+ | +−−−−−−−−−−+
| | (...) |
| +−−−−−−−−−−+
|
+−−−−−−−−−−−−−−−+ |
| (object) | |
+−−−−−−−−−−−−−−−+ |
| [[Prototype]] |−−−−+ +−−−−−−−−−−+
| argument |−−−−+−−>| (object) |
+−−−−−−−−−−−−−−−+ | +−−−−−−−−−−+
| | prop1: 1 |
aObj: null | | prop2: 2 |
| +−−−−−−−−−−+
b−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
As you can see, nothing has a reference to that object anymore.
And what is the easiest way I can test and see this?
Chrome has a pretty advanced memory profiler which can, amongst other things, show you the number of objects from a given constructor that are still in memory. More on their dev tools site here.
I have the following simplified code:
var obj = {
key1 : {
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
}
var objHashMap = {};
for(var key in obj){
objHashMap[key] = obj[key];
objHashMap[obj[key].aliases[0]] = obj[key];
objHashMap[obj[key].aliases[1]] = obj[key];
}
Now objHashMap has 3 entries, and all entries points at:
{
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
My question is weather all 3 points to the same object, or points to 3 different copies of the object?
objHashMap.key1 will have a copy of the value in obj.key. That value is a reference to an object. Both copies of that value refer to the same object. The you use the value of obj.key1.aliases[0] and obj.key1.aliases[1] to create two additional properties which also have copies of the reference, referring to the same object.
After this:
var obj = {
key1 : {
aliases: ["alias1", "alias2"],
prop1: someVal,
prop2: someOtherVal
}
}
...we have this in memory:
+----------------+
obj: ref-1654-->| (object) |
+----------------+ +-------------------+
| key1: ref-8754 |---->| (object) |
+----------------+ +-------------------+ +-------------+
| aliases: ref-6549 |---->| (array) |
| prop1: ??? | +-------------+
| prop2: ??? | | 0: "alias1" |
+-------------------+ | 1: "alias2" |
+-------------+
That is, we have a variable, obj, which contains a value that tells the JavaScript engine where an object is elsewhere in memory; I've shown that as ref-1654 above. Think of an object reference as a number that has meaning only to the JavaScript engine, like an index into a big array of memory. (The actual value of an object reference is something we never see.)
That object has a property, key1, which again has a value pointing to an object elsewhere in memory. That object, in turn, has aliases with another reference to an object (this time an array) in memory. The values of prop1 and prop2 in the object with aliases are unknown (they come from the variables someVal and someOtherVal, which you haven't defined for us).
Then this line adds another variable pointing to another object:
var objHashMap = {};
+----------------+
objHashMap: ref-8132-->| (object) |
+----------------+
| |
+----------------+
Your for-in loop only runs once, for the key "key1". After the first line:
objHashMap[key] = obj[key];
we have:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |---------+
+----------------+ |
|
|
| +-------------------+
+-->| (object) |
| +-------------------+ +-------------+
| | aliases: ref-6549 |---->| (array) |
+----------------+ | | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | | | prop2: ??? | | 0: "alias1" |
+----------------+ | +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+ +-------------+
+----------------+
Note how the key1 property in the new object contains the same value as the key1 property in the original object. They point to the same object.
Then you do:
objHashMap[obj[key].aliases[0]] = obj[key];
...which is to say
objHashMap[obj.key1.aliases[0]] = obj[key];
...since key contains "key1", which is to say
objHashMap["alias1"] = obj[key];
...because obj.key1.aliases[0] is "alias1". That gives us:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |-----------+
+----------------+ |
|
|
| +-------------------+
++-->| (object) |
|| +-------------------+ +-------------+
|| | aliases: ref-6549 |---->| (array) |
+------------------+ || | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | || | prop2: ??? | | 0: "alias1" |
+------------------+ || +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+| +-------------+
| alias1: ref-8754 |---+
+------------------+
Then again for this line:
objHashMap[obj[key].aliases[1]] = obj[key];
...which is:
objHashMap["alias2"] = obj[key];
...because obj.key1.aliases[1] is "alias2". So we end up with:
+----------------+
obj: ref-1654-->| (object) |
+----------------+
| key1: ref-8754 |-----------+
+----------------+ |
|
|
| +-------------------+
+++->| (object) |
||| +-------------------+ +-------------+
||| | aliases: ref-6549 |---->| (array) |
+------------------+ ||| | prop1: ??? | +-------------+
objHashMap: ref-8132-->| (object) | ||| | prop2: ??? | | 0: "alias1" |
+------------------+ ||| +-------------------+ | 1: "alias2" |
| key1: ref-8754 |--+|| +-------------+
| alias1: ref-8754 |---+|
| alias2: ref-8754 |----+
+------------------+
Yes, these point to the same object. Let me take an example to demonstrate the same:
var obj = {
key1 : {
aliases: [1,2],
prop1: 3,
prop2: 4
}
}
//initialize another object which will contain the same values.
var objHashMap = {};
for(var key in obj){
objHashMap[key] = obj[key];
objHashMap[obj[key].aliases[0]] = obj[key];
objHashMap[obj[key].aliases[1]] = obj[key];
}
//change the value of a key in objHashMap.
objHashMap["key1"].prop1 = 600
//now observe the value changed in other keys as well.
console.log(objHashMap[1].prop1);
console.log(objHashMap[2].prop1);
console.log(obj);