How do these parameters reference the object?

Hello,

I am having trouble understanding how the function’s parameters reference the object’s min and max.

When we access an object’s values, we have done it like this

const user = { name: 'John Doe', age: 34};

const {name, age} = user;

So I see that the deconstruction format is similar to what’s inside the function’s parameter but the function for this challenge simply puts the parameters of the object’s key it wishes to target.

This is how I would have expected the code to be just so you know what I’m thinking

const half = ({ max, min } = stats) => (max + min) / 2.0;

or something similar to this. I know that in the console.log we pass in the object stats but I would expect this to result

const half = ( stats {max, min} ) => (max+min) / 2.0;

  **Your code so far**

const stats = {
max: 56.78,
standard_deviation: 4.34,
median: 34.54,
mode: 23.87,
min: -0.75,
average: 35.85
};

// Only change code below this line
const half = ({ max, min }) => (max + min) / 2.0;
// Only change code above this line
console.log(half(stats))
  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50

Challenge: Use Destructuring Assignment to Pass an Object as a Function’s Parameters

Link to the challenge:

The specific object you are destructuring is set when you call the function, like here.

I think this is based on a misunderstanding. If I want to send in data to a function as a parameter, it doesn’t come in with a name. For example. If I have:

const myFunc = (myObj, myNum) => {
  // ...
}

const obj = { name: 'Kevin' }
const num = 127

myFunc(obj, num)

When myFunc receives those parameters, it has no idea what they are or what they were called in the other scope. All it knows, when it sees this:

const myFunc = (myObj, myNum) => {

is that it will receive two things. For the first parameter, it receives a memory address (a reference) and for the second parameter, it receives the number 127. Because data has a type in JS, it reads the type of what it is sent, but in theory you could send different data with different types.

So, in your example:

const half = ({ max, min } = stats) => (max + min) / 2.0;

Why would we need to reference stats? That was the name in the old scope. The function doesn’t know or care. This:

const half = ({ max, min }) => (max + min) / 2.0;

It is saying, “Look, you’re going to get an object here, and I want you to pull off those two properties and store them in variables in the function scope with those same names.” If you want access to the object itself too, then you’d have to do your destructuring outside the parameter list.

2 Likes

functions are generally meant to work with any object(which meets their perimeters criteria), not just the object named “stats” or any other name. The function half expects an object, which has the properties named “min” and “max”. How would that object look like? {min: 1, max: 5} for example. So in the parameters, instead of using for example a parameter to represent the object- (obj)=>console.log(obj.min, obj.max), we destructure it- ({min, max})=>console.log(min, max). If you compare the parameters from the two examples, you will notice both sides are “equal”, just like we would put it when we destructure an object: {min, max}=obj.

I see what you mean in the last sentence, we tell the function to reference the stats object when we console.log(half (stats) );.

My question was more based on, when we pass in the stats in the console.log, how does the system read it. You say that its saying "Look, you’re going to get an object here, and I want you to pull off those two properties and store . . . those same names.”

Which is the same logic here const {name, age} = user; So where I get confused is why the function is like this

const half = ({ max, min }) =>

Instead of how we usually see it like this
const {name, age} = user;

Obviously, this is just a deconstruction assignment but using the function ES6 method of a function

I would like to add to this, because it’s a common source of confusion. This is tangential to the main conversation, so feel free to ignore this!

Data in javascript is placed into memory, and then that memory location cannot change, so long as something is observing it (so yes, the data is a better behaved weeping angels from Dr. Who). If we assign a number or string to a variable, that value is placed in memory and the variable points to that memory location. If we assign an array or object to a variable, the same thing happens: the array or object starting point (think container) is assigned a memory location, and that variable references that location.

So long as something refers to that memory location, it remains. This is where confusion happens: with the primitive data types, you can’t alter the internal structure - updating a string creates an entirely new one at a new memory location, and refers us to that. But arrays or objects, Sets or Maps, we can alter the inner structure without affecting the container. So we can add to an array or change a property of an object without altering its original reference.

So when we pass an object into a function, both the original and the functions parameter reference the same memory location. We don’t know the original name of the thing, but we see that original memory location.

So when we deconstruct in parameters, as in this case, we don’t need to know the original name - we simply say “the thing at the memory location in the first parameter”, and then we deconstruct it.

Interestingly (though mostly a pointless thought exercise), the given property in the object and the deconstructed primitive point to the same location in memory, that of the value within the original object!

1 Like

You can think of

const half = ({ max, min }) => (max + min) / 2.0;
const result = half(stats);

as equivalent to

const half = (stats_arg) => {
  const {max, min} = stats_arg;
  return (max + min) / 2.0
};
const result = half(stats);
1 Like

AHHHH, THANK YOU. That brings everything to clear thought, THANK YOU. Would you say its bad idea to just personally think of


const half = ({ max, min }) => (max + min) / 2.0;
const result = half(stats);

As not the same but similar to this to think about when I get confused on how parameters reference an object

const half = ({ max, min } = stats) => (max + min) / 2.0;

I know this is wrong and its not how it works but its how I imagine it does since thats how we learned to deconstruct objects

I assume you mean the function half, not console.log.

I’m no expert, but the way I understand it, is if we have:

half(stats) 

We are passing a reference, the memory address that contains some data (read snowmonkey’s post for more on that). The function:

const half = (foo) => // ...

accepts that reference and stores it in foo. It doesn’t know and doesn’t care that it used to be stats. Technically it doesn’t even know what it is until it gets it. It gets some data and since JS associates type with data (a lot of languages associate type with the variable, no the data) it says, “oh, this is an object”.

When you do:

const half = ({ max, min }) => // ...

because you are destructuring, the compiler knows that you are sending an object and those two properties should be descructured off it. Yes, this:

const half = (foo) => {
  const {name, age} = foo
  // ...
}

would be functionally the same. So why do we have two ways to do it? They added a shorter way to do it. Some advantages that destructuring in the parameter list is a little quicker and easier. You also don’t have to create that extra variable, foo.

If you don’t want to destructure in the parameter list, then you don’t have to. There is nothing you can do there that you can’t do in the function. But if you want to work with other coders, you should get used to destructuring in the parameter list.

All new syntax looks weird when you first learn it. Don’t worry too much about how it works under the covers or the big “why” question. For now, just learn what it is and how to do it. The rest will come later.

I wouldn’t get this stuck in your head at all.

function myFunction(a = 42) {
  return a * 13;
}
console.log(myFunction(12));
console.log(myFunction());

is something different:

1 Like

Actually, thats not how I think about it in my head. Im thinking of this function’s parameter
const half = **({ max, min } = stats)** => (max + min) / 2.0;
as simply related to or the same as { max, min} = stats. Do you know what I mean?

This part right here is exactly what I am objecting to. This is a bad mental model to get used to because the = in a function argument list has a very specific meaning.

1 Like

Sorry, I meant to say that

const half = **({ max, min })

is the same as

{ max, min} = stats

After we pass the stats object like so

console.log(half(stats))

These two are completely opposite of each other.


All that is going on is an extra step where the manual destructuring of an input:

const half = (stats_arg) => {
  const {max, min} = stats_arg;
  return (max + min) / 2.0
};
const result = half(stats);

is automatically done for you

const half = ({ max, min }) => (max + min) / 2.0;
const result = half(stats);

This is destructuring - stats is in scope and we are destructuring off it.

This:

const half = **({ max, min } = stats)** 

This looks like parameter defaulting. The stats here is a default value which just happens to be in scope here.

Try this:

const half = ({ max, min } = stats) => (max + min) / 2.0;
console.log(half())

It works even though you are not passing anything to half. That is because the first parameter is undefined so JS uses the default provided, the object stats from the global scope.

There may be places where you want this, to use something as the default object. But that is not what you are thinking it is doing.

1 Like

I think the reason you might have this mental model is because the code you’re seeing explicitly names the stats object. But i think the reason there are objections to the mental model might be your function isn’t tied to any particular object.

If we’d wanted, we could have written half like this:

const half = ( min, max) => /*function body */

console.log(half(stats.min, stats.max) );

But the disadvantage of this? We have to know the order the function expects the parameters. With parameter deconstruction, we can pass in an object, not care about the order of properties or if there are More than we need, we can simply deconstruct in place, and get them. This would work, just as well as using stats:

console.log(half( {
  name: "Jimmy the Schnozz",
  avgScore: 108,
  min: 63,
  max: 219,
  wins: 33,
  loses: 8
}) )

There is no stats here, simply some guys bowling scores as an object literal.

The only requirement is that it contain a max and a min property, somewhere inside itself.

1 Like