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);
Related
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).
I am trying to learn typescript/js and one of thing i am doing is implement a rest-api using aws-lambda (severless tack). Now, I need to extract body payload to either a construct or just assign those values to variables.
Lets say I am sending following request to signup a user
POST {{userApiEndpoint}}/signup HTTP/1.1
content-type: application/json
{"username":{{username}},"password":{{password}}}
Now I want to extract this username and password from event.body. I have tried multiple things and everytime i am getting errors of string | undefined can't be assigned to string or something similar.
Things that i have tried
export interface User {
username: string | undefined;
password: string | undefined;
}
Option 1: const newUser = event.body? as User; got an error that says Cannot find name 'as'
Option 2: const newUser = event.body as User; got an error which says Conversion of type 'string | undefined' to type 'User' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Option 3: const body = JSON.parse(event.body); got an error which says Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
I am not sure what else to try.
Option 3 should work.
Edit: unless you have explicitly typed your event type as APIGatewayProxyEventV2, in which case the body is of type string | undefined, and the user is:
user = JSON.parse(event.body ?? "") as User
export interface User {
username: string | undefined;
password: string | undefined;
}
// event explicitly typed as APIGatewayProxyEventV2
// the body is typed as string | undefined
const event = {body: '{"username": "foo", "password": "bar"}'} as Record<string, string | undefined>
const user = JSON.parse(event.body ?? "") as User
console.log(user.password)
// Option 3
// the body is typed as any
const event1 = {body: '{"username": "foo", "password": "bar"}'} as Record<string, any>
const user1 = JSON.parse(event1.body) as User
console.log(user1.password)
I have used Sequelize with mysql database in my node js application. I want to fetch the value from the db and passed in to the bash script, consider the following code email is fetched from db and stored it in variable but I couldn't access outside of then function
desc users;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| value | varchar(255) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
6 rows in set (0.24 sec)
code:
User.findOne({where: {name: 'name'}}).then(function(user) {
var name = user.value
});
User.findOne({where: {name: 'email'}}).then(function(user) {
var email = user.value
});
User.findOne({where: {name: 'age'}}).then(function(user) {
var value = user.value
});
var child = exec('bash user.sh name age email')
How to access variables (name, email, age) outside then function in node js?
var child = exec('bash user.sh email')
User.findOne({where: {name: 'usr1'}}).then(function(user) {
var email = user.email;
console.log(child);
},child);
The database query runs asynchronously, So if you want to use any result from the query, you must write that code inside then.
For example -
User.findOne({where: {name: 'usr1'}})
.then(function(user) {
// Do your stuff here.
var email = user.email;
var child = exec('bash user.sh email');
});
The most intuitive solution would be to use async await
(async () => {
const email = await User.findOne({where: {name: 'usr1'}});
const child = exec('bash user.sh email');
})();
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 a mongo collection like the following (Foo(X) == keys; Bars == values): EDIT- I come from a relational database background. Obviously my collection doesn't look like the below, but you get the idea...
+--------+--------+--------+
| Foo1 | Foo2 | Foo3 |
+--------+--------+--------+
| Barbar | Barbar | Bar |
| bar | Bar | BarBar |
| Bar | barbar | barBar |
| ... | ... | ... |
It's important for me to allow my client to filter the data. Sometimes, all columns will have a filter, other times no columns will have a filter and anywhere in between. Currently, I'm handling the issue as follows:
Client
Var aFoo1Filter = ["bar"]
Var aFoo2Filter = ["Barbar", "BarBar"]
Var aFoo3Filter = ["barbar", "bar"]
//Where the user can affect the array through some other code
Server
Meteor.publish("foos", function (aFoo1Filter, aFoo2Filter, aFoo3Filter ) {
return FooCl.find({Foo1: {$in: aFoo1Filter},
Foo2: {$in: aFoo2Filter},
Foo3: {$in: aFoo3Filter}},
{limit: 10});
});
I'm hoping to simplify this by passing through just one object or one string from the client to the server, but neither attempts have worked. See my attempts, below:
Attempt #1 - Passing Through a String
Client
Var sFilter = "Foo1: {$in: [\"bar\"]},
Foo2: {$in: [\"Barbar\", \"BarBar\"]},
Foo3: {$in: [\"barbar\", \"bar\"]}"
Server
Meteor.publish("foos", function (sFilter) {
return FooCl.find({sFilter},
{limit: 10});
});
//////////////////
Attempt #2 - Passing Through an Object
Client
var oFilter = {
Foo1: "bar"
}
Server
Meteor.publish("foos", function (oFilter) {
return FooCl.find({oFilter},
{limit: 10});
});
I don't have my machine with me at the moment, so I can't provide more detail on the type of error thrown. Hopefully will have some more info up tonight. Thanks for any help!
The easiest way to solve this problem is to subscribe using a selector:
Client
var selector = {Foo1: {$in: aFoo1Filter}, Foo2: {$in: aFoo2Filter}};
Meteor.subscribe('foos', selector);
Server
Meteor.publish('foos', function (selector) {
return FooCl.find(selector, {limit: 10});
});
However, it's important to recognize that this gives the client the ability to request any documents from the FooCl collection that she wants. An improved solution is to limit what can be requested by using match on the selector. For example:
Meteor.publish('foos', function(selector) {
check(selector, {
Foo1: Match.Optional({$in: [String]}),
Foo2: Match.Optional({$in: [String]})
});
if (!_.isEmpty(selector)) {
return FooCl.find(selector, {limit: 10});
}
});
This will ensure that selector conforms to an acceptable pattern before any documents are sent to the client.