Object of object as function parameter

As you can see from my code sample, I am wondering why the following thing doesn't work. I have an object with an object as a property (will call it prop in the text below). When I assign the values to the prop in the function, those values are there, because obviously it is passed by reference, but I don't understand why the prop can be referenced to point to another object.

In the case of setting the prop to another object, I just get the empty object, as it is in start. What am I missing here?

const person = {
  basic: {}
}


function initPersonBasics(b) {
  // doesn't work
  b = {
    firstName: 'John',
    lastName: 'Doe'
  }

  // works
  // b.firstName = 'John';
  // b.lastName = 'Doe';
}




initPersonBasics(person.basic);
console.log(person);

Upvotes: 0

Views: 34

Answers (2)

axiac
axiac

Reputation: 72366

Inside the initPersonBasics() function, the argument b behaves like a local variable. When the function starts, it is already initialized with the value of the first argument of the function (person.basic).

But the statement

b = {
    firstName: 'John',
    lastName: 'Doe'
}

puts a different value in b; it doesn't change person.basic in any way.

As you already noted, if you don't assign a new object to b and set b.firstName and b.lastName instead, the values are stored in person.basic. This happens because JavaScript assignment doesn't copy the objects but stores references to them.

There are several ways to make it work as you want. You have already discovered one of them: store the values one by one in the properties of b (which is an alias of person.basic during the execution of the function call).

Another option is to use Object.assign():

function initPersonBasics(b) {
    Object.assign(b, {
        firstName: 'John',
        lastName: 'Doe'
    });
}

Please note that it doesn't work in older browsers (and even in some newer ones). Carefully check the Browser compatibility section.

Another option (that works in all browsers) is Object.defineProperties() but its syntax is more verbose:

function initPersonBasics(b) {
    Object.defineProperties(b, {
        firstName: {
            value: 'John',
            writable: true,
        },
        lastName: {
            value: 'Doe',
            writable: true,
        }
    });
}

Please note that if you don't mention writable: true for a property, it becomes read-only and cannot be assigned to (and no error is reported).

Upvotes: 2

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174457

const person = {
  basic: {}
}


function initPersonBasics(b) {
  b = {
    firstName: 'John',
    lastName: 'Doe'
  };

  console.log(b);
}

initPersonBasics(person.basic);
console.log(person);

The reason is that you are re-assigning b to point to another object inside initPersonBasics. But that doesn't change where person.basic points to.
What you are doing is similar to this simple code:

function foo(i) {
    i = 42;
}

let j = 10;
foo(j);

You wouldn't expect j to be 42 after the call to foo, would you?

Upvotes: 1

Related Questions