This course has been updated! We now recommend you take the JavaScript: The Recent Parts course.
Transcript from the "Lazy Expressions" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Kyle Simpson: Let's talk about the values that we put into that default expression. Most of you probably assume it's just simple stuff like constants. But there's no requirement that it has to be a constant. It can be any valid JavaScript expression, not statement, but expression. Same kind of rules as an arrow, concise body of that.
[00:00:22] Any expression that's valid could be there. So what if we made it a function call? Like for example bar, that's totally valid. And if there was a function bar here, that said console dot log And put a little exclamation mark. So the question is, in this particular program with no executions.
[00:00:48] How many times do you think bar has been called?
>> Speaker 2: None, until you call foo.
>> Kyle Simpson: There's only two rational answers here, either 0 or 1. So how many of you would vote for a 0? It's not being called at all. How many of you vote for 1, it's called once, okay.
[00:01:12] How about online? Let's take that poll, I know we have to wait 15 seconds. Let's take the poll online. Raise your hand if you vote, for online, raise your hand if you vote for it's been called once versus its been called zero times.
>> Speaker 2: Or just type it in zero or one.
[00:01:27]
>> Kyle Simpson: [LAUGH] Okay, so that's the question. How many times is bar called?
>> Kyle Simpson: Okay, seems like we're getting a bit of a mix, but maybe a little bit more weighted towards It's called once. Okay.
>> Kyle Simpson: So that's why we talk about this. That's why we asked these questions, cuz I want you to understand this stuff.
[00:01:52] I don't want you to just make assumptions or guesses or whatever, it's important to understand how JavaScript works. So ES6 introduces a notion of what's called, a lazy expression. This expression is not evaluated unless and until it is needed. So the correct answer here is, not been called at all yet.
[00:02:10] Cuz it hasn't been needed yet. If I say foo(1) how many times has bar been called? Still zero, cuz it still hasn't been needed yet. Okay? But, as soon as I call foo where it is needed, then it gets called. And every time I call foo, I'm gonna get it printing out that exclamation mark every time.
[00:02:33] Okay?
>> Kyle Simpson: You with me? Yes?
>> Speaker 3: And it's a new invocation each time you call foo.
>> Kyle Simpson: It is an absolute, the entire expression is re-evaluated every single time. It's kinda like you wrap the expression in a function that's not there and then you call that function. Whatever it gives back is what you put in, okay?
[00:02:55] So it's, in essence, a lazy expression. We don't really have lazy expressions in JavaScript. But it's sort of syntactically like that, okay? Now you might be wondering why on Earth would I want a function that would be called over and over? Or why would I use this? Well, one example for where you might use it is if this one was like a unique ID generator.
[00:03:16] And you wanted to be able to pass in an ID, or have it automatically generate one if I don't pass one, okay. That's one usage of making a function call there. Another usage, this is kind of an interesting little trick, you could make one called required, that said for example- I'm gonna go ahead and script the server.
[00:03:37] This one could say,
>> Kyle Simpson: Could throw a Java Script error.
>> Kyle Simpson: And you could say that. So if they don't pass in the ID, a JavaScript there is thrown saying, hey the parameter was required, okay? Yes.
>> Speaker 4: [INAUDIBLE] be a way to refer to foo, within the required function, so you could name it?
[00:04:02]
>> Kyle Simpson: No, there's no way to do, like a self reference, or something. You could manually say, like this, double that up and then say,
>> Kyle Simpson: You could do that if you wanted to. But there's no like, self reference thing going on. Okay, so any expression that we wanna put there we can put there, and there's a variety of little usages that we can do.
[00:04:32] The point is that we don't have to do the imperative form of testing against undefined, that's automatically built in for us. We just do the declarative form. And once you become familiar with that, now that will jump out at you as being a lot more self-explanatory. That's the purpose of the declarative form, okay?
[00:04:54]
>> Kyle Simpson: Any questions about using default parameter values? Let me push your understanding just a little bit beyond what you normally comfortable with, okay. We talked about scoping a little bit before. It turns out that technically the spec requires that each variable, that the parameter list as a scope, and each variable kind of gets its own list or whatever.
[00:05:20] So you can do self references to other parameters, as long as they've already been in the list. So I could say x is equal to ID. So now x is going to default to the value that ID got set to, whether affirmatively or defaulted to. So it's going to go in a left to right fashion right.
[00:05:40] So we can do a self reference. You can't go in the other order though. You can't do that before, because the ID doesn't exist yet. It's kind of like a let declaration, in that sense. It doesn't exist yet, so now you'd be accessing the ID inside of its temporal dead zone, if you will.
[00:05:59] But what about this?
>> Kyle Simpson: I'm gonna see jow close you're paying attention, and how good you are guessing. What do you think would happen if I said,
>> Kyle Simpson: So I've got an f that defaults to this function which returns x. So is it returning the x from here, or is it going to return that x?
[00:06:54] All right, so let's talk about these particular cases for just a moment. What's happening with the scope of the function when the function shows up in one of these lazy expression positions? That's essentially the question that we're are trying to tackle. So if I pass in no foo at all, x is going to default to 2.
[00:07:11] And f is going to default to this function, which is closing over some x. The question is which x is it closing over. Is it closing over the x from the parameter list, or the x from the outer scope?
>> Kyle Simpson: Okay. So most people are gonna say, yep, it's going to close over the parameter list.
[00:07:36] So if we try this,
>> Kyle Simpson: We in fact get the value to close over the parameter list. Well,
>> Kyle Simpson: What do you think now?
>> Speaker 5: It's going to be fine.
>> Speaker 6: Hope that doesn't change it.
>> Kyle Simpson: So we think it should still return 2, right?
>> Speaker 6: We hope so.
[00:08:11]
>> Kyle Simpson: We hope so. Well?
>> Speaker 6: No, cuz it hasn't been called on yet.
>> Kyle Simpson: Let me give you just a moment to think. [INAUDIBLE] Is it gonna return 2, or is it gonna return 5? Which x is it?
>> Speaker 6: 5.
>> Speaker 5: It's gonna be 5.
>> Speaker 6: It should be 5.
[00:08:31]
>> Kyle Simpson: Isn't it a pain when somebody asks these annoying little esoteric. This is the stuff that they put on [CROSSTALK]
>> Speaker 6: It should be 5, because it doesn't actually get called until the consult function. And by then x is-
>> Speaker 5: No, the function already closed over X. It should return 2.
[00:08:50]
>> Kyle Simpson: All right, so if we run this in Chrome,
>> Kyle Simpson: We think, good, it's 2. That makes sense, except Chrome has a spec bug. It's supposed to be 5.
>> [LAUGH]
>> Speaker 6: No. [LAUGH]
>> Speaker 5: No, no.
>> Kyle Simpson: Babel has this bug as well. What's happening here is that a var at the top level is taken as a duplicate declaration, when there was already an x.
[00:09:20] So the x equals 5 is assigning to the x parameter that the function was closed around. So that's why it's still closing over the one that you thought, but we already changed its value. It sucks, doesn't it. [LAUGH] Okay, a little take away here, don't try to write confusing code.
[00:09:38] But I push on you with confusing code to help you understand where the edges of reasonability are, okay? I have virtually never in my experience found a case where I put an inline function expression up in my thing. Especially not with arrow functions or whatever, I don't recommend doing that.
[00:09:58] Because then you're pushing on those edges of weird stuff that people have to think about.
>> Speaker 7: Personal question, is this stuff talked about in your ES 6 chapter?
>> Kyle Simpson: Yes, I cover this stuff.
>> Speaker 6: Question from the chat room was could you go over that again?
>> Kyle Simpson: Yes, in this particular case, the spec says the var- and I missed this.
[00:10:20] I was confused by this, and somebody had to walk me through this part of the spec to get it. The spec basically says that the var x here is not creating a new x in a new interscope. But actually, the x that already exists as part of the parameter, it's basically kind of a replacement, or just a no op of that one.
[00:10:42] Because there's already an x in the scope of the function, cuz that's the way it always worked from before. So they had to preserve that capability, once all this newfound fangled stuff that we did with parameters came along with ES6. So this var x is basically the var is a no op.
[00:10:58] So the line 4 is just x equals 5, which is changing the param it defaulted it to, now to the value 5. And this closure is a closure, a live link, not a snapshot. So now the function returns the current value of x, which is the value of 5.
[00:11:14] That's what it's supposed to be.
>> Speaker 3: It's the same principle as putting the unused variables in your parameter list, really.
>> Kyle Simpson: Say, that again. Tell me why you said that.
>> Speaker 3: In the previous example, we used unused variables in your parameter list, so you could assign them in the function.
[00:11:30]
>> Kyle Simpson: Yeah.
>> Speaker 3: Same principles apply in here.
>> Kyle Simpson: Okay, sort of, yeah. The fact that parameters are variables that we can assign to, is absolutely true, yeah. A lot of people think that the parameter list should be treated strictly as its own scope. For the purposes of TDZ, it is its own scope.
[00:11:46] But for the purposes of preserving the fact that they were always kinda one in the same, before this special case of var, it ends up just being a redecoration. Yeah?
>> Speaker 8: So what if I you change your var to let?
>> Kyle Simpson: I don't know. There's that would probably be in error.
[00:12:07] I think that's a static error. Because you're not allowed to do let x in the same scopes. So I think the spec would probably throw an error there, but I don't know. The problem is we can't trust either Chrome or Babel at this point, because they still have this problem.
[00:12:24]
>> Speaker 8: So is the parameter list x essentially a let in ES 6?
>> Kyle Simpson: Yes.
>> Speaker 8: Okay.
>> Kyle Simpson: For most purposes, yes.
>> Kyle Simpson: All right. So stick to the stuff that makes sense, like making a simple function call or using as a simple direct primitive literal or something like that.
[00:12:47] Default values will be helpful.