Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course

The "Exercises 18-19" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:

Exercise 18 involves using both the reduce and map functions to reduce multiple boxart objects to a single value. Exercise 19 demonstrates how to have the reduce function return a different type than the accumulator. Jafar also talks briefly about prototypical inheritance.


Transcript from the "Exercises 18-19" Lesson

>> Jafar Husain: So let's retrieve the URL of the largest box art. Okay, so now, this is an interesting one because notice that reduce is gonna have, it's kind of a challenging one because sometimes when you're using your accumulated value, right. Needs to be, sometimes the result you want is not the same as the accumulated value you'd use for reduce.

Let me show you an example. So I've got to compare box arts to each other, right. And I want to come up with the URL of the largest one. So what I'm gonna do is I'm just going to call reduce without an, I'm gonna my arrow function here.

So we're in a function that takes accumulated and current, and if the accumulated width times accumulated height,
>> Jafar Husain: Is larger than current width times current height. Actually I think we can shorten this into the same ternary expression that we used last time. We return accumulated versus current. So it's almost exactly the same as last time, right.

We just compare the current box art with the last box art, and if the current one is is larger, we return the current one, if the if the one we've accumulated thus far as large we return that one. I'm gonna close this reduce off, but I'm not done yet.

I've picked the largest box art but remember that the goal was to actually return the URL of the largest box art. So in this case, I'm expecting, because I think 425 by 150 is the largest, I'm not sure actually. I think I'm expecting to just get this. Anybody want to tell me what operator I would also have to chain off of reduce to just grab that one property?

>> Speaker 2: [INAUDIBLE] to map it?
>> Jafar Husain: Yeah, I'd have to map it. Now I've got an array containing just one box art, and what I want is an array containing just the URL of that box art. So we're substituting the box art object for just the URL inside.
>> Jafar Husain: I think that's right.

>> Jafar Husain: Where's my semicolon here?
>> Jafar Husain: Yeah, that worked. So that's reduce. Now let's try reducing with an initial value. One of the challenging things about reduce is that sometimes, the types of the object in the collection is not the same type as the object we want to come out of reduce.

So the result of reduce will usually be the same type as whatever the accumulated value is. So if you allow the accumulated value to just be the first item in the array, well then you know the type that comes out of reduce gonna be the same type as what's inside of the array.

However, sometimes you don't want that. Sometimes if you provide your own accumulated values as a starting point, that last optional argument, then you would expect the result to come out of reduce to always be the type of that accumulated argument. That's not always true in JavaScript cuz there's no types and, but generally speaking that's true.

So here I have an array of videos. But what I'm trying to get is a, we want, interesting. We're trying to create a map so we have an array of IDs and titles. And we want to create is a map where the ID is the key and the, let me see, the value is the title.

So let's show you what I mean here, there's an example down here I believe. There isn't, that's a shame. Here we go. So I would expect an array containing only one result, where we have a map of all the video ids, and their titles. Whereas now we have an array of ids and titles, we want to get this.

So we're taking all these objects and aggregating them up into one big map, right? But notice that what comes out at the end isn't an object that looks like ID and title. It's a different type, it's this map with all that stuff. And so what I'm gonna do is I'm wanna give it an accumulator value that's an empty map.

Because what I wanna do is I wanna take all these titles, I wanna suck their data out and I wanna jam it in to this accumulated map, so that in the end all and left with is that accumulated map with all the data inside. So let's try this.

So I'm gonna use my accumulated map and notice here down here in passing an empty map as my accumulated values. That's what I want to use as my accumulated value, every single time a new video comes in, I'm just gonna pull the ID and title and stick it in there.

Now, here is one definition that would work actually. But I'm not gonna do it, which is accumulatedMap[] = video.title. If we did this, it would work.
>> Jafar Husain: We of course have to return the accumulatedMap. Does everybody see why that's gonna work? So we pass in an empty map and for every single item,

>> Jafar Husain: So current is going to be this item, right down here. So the video is gonna be this item right up here.
>> Jafar Husain: First, and then it's gonna be passed into the accumulatedMap. And now we're just gonna use this, we're just gonna add the data inside of this video, id and title, to the accumulatedMap and return it.

So the next time around, the same map will be the accumulatedMap and we'll just have a different video. So now it will be this one. So we suck the ID and title out, add it to the accumulatedMap, return that accumulatedMap, and once again, we just keep going like that until finally we've exhausted everything and we return the accumulatedMap.

Now that will work in JavaScript and I don't want us to do it. I don't want us to do it for one simple reason. Inside of all of our functions that we pass to these operators, map, filter, reduce, here's what I want you guys to do, never ever change a value.

Inside of map, your map function, inside of your filter function, your projection function, your predicate functions, I never ever want you to change a variable, ever. And what we're doing here is we've got this accumulated map and we're changing it. We're actually changing what it is by sticking some properties onto it, does that make sense?

What I mean when I say change it, I can do this without ever changing the accumulatedMap. I can do it without changing it all. Here is how I'm gonna do it. Well, here's one way of doing it. Which is, I could actually clone the map. Not so efficiently, but this would work.

Does everybody know why this would create a clone of the map? I'm turning this map, I'm serializing into a string, that's adjacent string, and then I'm parsing that string, so I've actually created a complete copy of that map. So if I did this,
>> Jafar Husain: I would accomplish what I'm trying to accomplish was I'm trying to avoid changing values.

So in this case I'm creating a brand new value, and I'll set a property on that. That's okay, as long as I'm not, the point is I don't wanna change a value that's passed in to me. Cuz let's say I have a value, and I call a function I pass that value in, and somebody else mucks with it, they change it.

That's actually kind of complicated, because I never know whether somebody's gonna muck with my value or not. Ideally they would create a copy, and so I would be able to hold on to my object and they would be able to do whatever computation they needed to do. So this concept of mutation, of changing an object once you have it, actually creates a lot of complexity in an application.

And notice that all the functions I've been showing you up to this point, they don't change arrays, right? Maps doesn't change an array. Filter doesn't change an array. Map creates a new array, right? Filter creates a new array. All of the expressions that we've been writing thus far never change anything.

They just create new data from old data, and that turns out to be a really wonderful property in a program. So without explaining necessarily why, what I'd like you to do is avoid changing any variables that you don't own and you haven't introduced yourself inside of these functions.

And the way that you can do that, JavaScript has actually got a neat trick, which allows you to do this without this, which is much more expensive. It's actually a cheap way of cloning an object. Who here is familiar with prototypal inheritance in JavaScript? So we have a few people.

In JavaScript, we have this notion of prototypal inheritance, and what that means is, if I have a, actually, I'll show it in a console.
>> Jafar Husain: So let's say I create a person.
>> Speaker 3: Just for reference, our advanced JavaScript course really covers this in very specific detail.
>> Jafar Husain: Okay, so I'll be very brief, I'll just show the concept.

So I've created a person and now let's say I want to create a person object that has all the same another object that has all the same stuff inside a person. But I also want to add some stuff to it, so I don't want to change the person object.

I wanna create a whole new object that has all the same stuff inside a person but extra properties as well. So I'm going to create-
>> Speaker 3: [INAUDIBLE] console process.
>> Jafar Husain: Absolutely.
>> Jafar Husain: This is a little bit odd, but what this does is it doesn't create a clone of, this is not good.

>> Speaker 4: Can you escape?
>> Jafar Husain: Good, good call. It doesn't create a clone of person, but if, notice that if what happens if I look up,
>> Jafar Husain: The name, it looks like it creates a clone. It looks like it's actually created a copy, because it's got the same name property.

But what's actually happening is that every object in JavaScript has what's called a prototype. So it actually has a pointer to another object which it's using as its prototype. So another way of saying that is every object in JavaScript is like a linked list. So another person is actually just an empty object and I can prove that to you.

>> Jafar Husain: It's empty. It's actually got no properties in it. So it's got no properties in it. How does this work?
>> Jafar Husain: Well the way it works, is that another person actually has a pointer to person. And if you attempt to look up a key on another person and that key is not found, it follows the link to the next object.

And then it finds it on person and it stops there. Does that make sense? So we've created a linked list of objects. Every JavaScript is in fact a linked list of objects, and if you attempt to look up a property on them, and it's not there, it'll keep following the chain up.

And so, in essence, it's actually a cheap way, in some ways, to think about it as copying an object. Because, instead of just going through all the properties and then copying them into another object, what you've actually just done is you just created a new object with a little pointer to the old one.

And so I can use that technique here to avoid ever changing the accumulated map and instead,
>> Jafar Husain: Make a very cheap quote unquote copy of it.
>> Jafar Husain: So what I've done here is I've made a whole new object, in fact, I'll even name it differently so it's clear.

>> Jafar Husain: And since I created this object I can muck with it all I want. The whole point is to avoid changing somebody else's objects. So if an object gets passed into a function, you shouldn't muck with it. Not in a map or a filter or reduce function. You shouldn't muck with other people's objects, but here I've created the object myself, right.

And so I can set this one property here and return it, and it works. So what we keep doing is we're actually creating new little maps that hold onto all the old maps which are also still there. Now, ad we have never changed any of them, right? And the end result is the same, that we have a a single map,

>> Jafar Husain: I'm not sure where the problem is but,
>> Speaker 4: It is pretty interesting looking a little [INAUDIBLE]
>> Jafar Husain: Hm?
>> Speaker 4: I got nothing.
>> Jafar Husain: Yeah, so we're just, you know, it's a cheap way of copying an object. Instead of actually copying the object, we create another another empty object and create a little pointer to the old object.

And then every time you try to look up something on the new object, if it can't find it, it walks the line until it can find an object with that property, yeah.
>> Speaker 5: So if you create, an object.create and let's say you changed the original copy.
>> Jafar Husain: Then it'll muck with a new, then it'll make the new copy look like it's changed.

Right, so we can actually try that right here because, remember it's not really, it hasn't copied the data, it's actually just holding on to the old data. I think that's actually a good example so we should check that out.
>> Speaker 5: So you could still have issues doing it this way too then?

>> Jafar Husain: Yes, you could. Somebody could muck with the original object and then you'd be in a bad place. I still have that open?
>> Jafar Husain: The goal here is, JavaScript can't make sure that nobody mucks with an object. Well, that's not entirely true. You can call object.seal, which is a way of actually locking down an object to avoid anybody making any copies to it.

And so every now and then that's actually a nice thing to do. If you want to make sure that nobody mucks with your object, you can call object.seal on it, and then nobody else can muck with it. But some languages can actually statically verify that nobody can change your objects and that's kind of nice.

So in JavaScript we're just sort of relying on the honor system here, in this type of programming. So who's familiar with the term functional programming? Quite a few people, right. The idea behind functional programming is very much this, you'll always take data in and create new data. You don't change anybody else's data, and that turns out to actually be a very simple and powerful way of building a program.

And up till now it's pretty much all we've been doing, right? We've taken arrays, creating new arrays. We've never changed anything except in our implementation of map and our implementation of filter, where we've created a new array that we own, and modify that right. That's okay. Creating your own objects and modifying them is fine.

But if you think about it up till now we've never ever taken somebody else's object and changed it. And I want you to continue doing that as we go over time. Think that way inside of your map and your filter function, it's a smell. If you're having to change an object that was passed into you.

That make sense?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now