Check out a free preview of the full The Good Parts of JavaScript and the Web course:
The "Function Challenge 7" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:

In this challenge, you will write the counter() and revocable() functions.

Get Unlimited Access Now

Transcript from the "Function Challenge 7" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Douglas: When you say we do some object-oriented programming? Yeah, all right. Yeah. So we're gonna do something with an object now. We're gonna write a counter function that returns an object containing two functions that implement an up down counter, hiding the counter. So we'll call the counter factory and pass in an initial value, and it will return an object containing an up method and a down method, and when we call up, it will add one to the value and return it.

[00:00:34] When we call down, it will subtract one from the value and return it.
>> Douglas: And I'll give you a hint, no global variables. No this, none of that crap.
>> Speaker 2: We don't need any of that.
>> Speaker 3: Darn it.
>> Speaker 2: I always use global variables everywhere. It's what Ben taught me to do.

[00:00:56]
>> Speaker 3: I did not teach you to do that.
>> Speaker 2: What could go- Ben always says more globals.
>> Speaker 3: It's exactly the opposite of that.
>> Speaker 2: More globals.
>> Douglas: So here is counter, it takes a value, it returns an object containing two functions. The first one, the up function, adds one to the value and returns it.

[00:01:16] The other one, the down function, subtracts one from the value and returns it. So who got something that works? Brilliant. If you didn't get it, write it down, cuz you'll want to refer to this pattern later. So this is very similar to what we talked about yesterday, where we've got two functions inside of a closure which are both sharing common data.

[00:01:36] This is a very simple example of that, but basically, all object constructors are gonna follow this pattern. Any questions about this? Okay, want to do another one? So this next one, I promise, is going to sound much worse than it actually is, okay? So, make a revocable function that takes a binary function and returns an object containing an invoke function that can invoke the binary function and a revoke function that disables the invoke function.

[00:02:06] Okay, so let me explain what's actually going on here. This is something that might have some security properties, and that we might have some guest code that we allow into our system, and we want it to be able to run as long as we want it to, but at any point, we want to be able to cut it off.

[00:02:24] And we don't want to have to rewrite our existing APIs in order to accommodate that. So this is a variation on the limit function that we wrote earlier. In fact, you might want to refer to your implementation of limit when you're doing this one. Except in this one, instead of keeping a count about how many times you get to do it, we will have a separate function called revoke, which will, when we call it, cause the thing to stop working.

[00:02:50] Okay, so we'll call our revocable factory, we'll pass in any existing function, in this case, the add function, and it will return an object containing two functions. One of them will be the invoke function, which is the revocable add function. And we can give that function to the third party, but we will hold on to the revoke function for ourselves.

[00:03:11] So the revocable add function will work just like add until we call the revoke function. At that point, all it does is return undefined. Everybody clear?
>> Speaker 2: So it's basically, what we really need, the dot dot dot arguments and then [INAUDIBLE].
>> Douglas: Yeah, we want this to work for all functions, right?

[00:03:34]
>> Speaker 2: Yeah, and that only works for.
>> Douglas: For binary. And actually, anything that works for binary, probably works for unary, because we're just gonna pass undefined as the second argument, then it gets ignored.
>> Speaker 2: So [INAUDIBLE] could just plan ahead.
>> Douglas: Yeah, if you knew we never used more than ten routers, you could do that, but who wants to do that?

[00:03:56] Yeah, it's awful.
>> Speaker 3: But you could call, if inside, you could always just call our [INAUDIBLE] you can pass that wherever?
>> Douglas: You can.
>> Speaker 3: Okay.
>> Douglas: So you can do that today, it's just inexcusably ugly, and I don't want to waste your time with it, so we're not gonna do that.

[00:04:16]
>> Speaker 2: [INAUDIBLE] Argument zero, argument one, argument two, you can't just pass in the arguments object.
>> Douglas: Actually, you can't, yeah, which is kind of a problem.
>> Speaker 2: It didn't work for me that way. That was my go to, to try that [INAUDIBLE] Good.
>> Douglas: You probably did something wrong, which is great.

[00:04:39]
>> [LAUGH]
>> Douglas: Keep doing that.
>> Speaker 3: It's arguments?
>> Douglas: Arguments.
>> Speaker 3: So if you get arguments in a function, and you call another function inside of that, passing arguments, you're passing an array to that function, you're not passing each of the arguments in that array.
>> Douglas: Right.
>> Speaker 3: That's why it doesn't work.

[00:05:01]
>> Douglas: But you could then use apply to spread it out.
>> Speaker 3: In ES6 or?
>> Douglas: In ES3.
>> Speaker 3: Okay.
>> Douglas: Yeah.
>> Speaker 3: Array.apply [INAUDIBLE]. I'm sorry, [INAUDIBLE] arguments.
>> Douglas: No, unfortunately, it's Function.apply. So, we're not doing that. It's too awful.
>> Speaker 3: That's right, you showed us yesterday. And you said it was ugly, so I ignored it.

[00:05:25]
>> Douglas: Yeah, it was good that you ignored it. Okay, we ready for revocable? So here's revocable. It takes a binary function and returns an object containing an invoke method and a revoke method. The invoke method looks to see if binary is undefined. If it isn't, then it will call it, passing the first and second argument.

[00:05:49] Otherwise, it doesn't do anything and returns undefined. Revoke function sets binary to undefined, thereby disabling the invoke function. So who's got something that works? Very good. Anybody do something different? Something notable?
>> Speaker 3: I put a variable okay which I set to false, but it's the same thing.
>> Douglas: That is okay, yeah.

[00:06:12]
>> Speaker 3: Thanks. So, I open this up, so I create. We made this object, which is in the, and I look in the console at my object, and I want to introspect it. So I expand it. Where's binary in there? It's obvious, it's not exposed publicly as a part of this object, but it knows about it.

[00:06:39]
>> Douglas: Right, binary is hidden in the function scope of the revocable function, and is available only through its closure. And the only functions in the universe who have access to that closure are invoke and revoke. So that's why this is something that we can build secure systems out of.

[00:06:58] You know, if we were to take your okay flag and put it in the object itself, then the attacker could go to the object and turn it the other way.
>> Speaker 3: Right.
>> Douglas: So that wouldn't accomplish what we want to do here.
>> Speaker 3: So we could obviously look at the source, but you'd obviously, I mean, it's.

[00:07:16]
>> Douglas: Right, so we assume that the attacker can always look at the source. But they can look at this source and it doesn't help them, right, unless they were there at the creation of the object, they can't get to it. They can't get to binary.
>> Speaker 2: So revoke is irrevocable in this case.

[00:07:35]
>> Douglas: That's right, this is a one-way trip. Now, we could design this to work a different way. Using his okay variable as an on-off switch, we could provide a second function or maybe an argument to revoke which could reverse it. But generally, I prefer systems where once we cut them off, it's off, and we don't have to worry about something turning it back on again in an unexpected way.

[00:08:01] Yeah?
>> Speaker 4: Since you're not explicitly returning undefined in the invoke?
>> Douglas: Mm-hm.
>> Speaker 4: Is this a case where you said, you flip flop on whether you should return undefined or not?
>> Douglas: That's right. I mean, I like, the idea of being explicit, and I also like not doing anything I don't have to do.

[00:08:18]
>> [LAUGH].
>> Speaker 4: Kind of at odds with each other.
>> Douglas: Yeah, exactly. There's a real conflict there. But most of the time, doing the right thing and doing the right thing are obviously the same thing. This is one of the cases where it isn't so much.