DEV Community

Bram Adams
Bram Adams

Posted on

Lexical Scoping in Javascript and Improv

Summary

  1. What is lexical scoping?
  2. What are closures?
  3. Lexical scoping is a technique used in improv
  4. Comedic callbacks and Rule of Three

What is lexical scoping?

Lexical scoping is a computer science concept used to manage and read variables. Lexical scoping is used by the parser (the interpreter of our code) to determine which variables belong to which scope. This is best illustrated with an example: Some key words:

  • variable: a value that can change over time, not constant
  • function: a block of code that can be run by a computer by "invoking" it using parentheses, like putOnPants()
  • closure: we'll get to that soon ;)
function sayMyName() {
    let name = 'Bram'; // name is a local variable
    function displayName() { // displayName() is the inner function, a closure
        console.log(`Hi ${name}!`); // use variable declared in the parent function
    }
    displayName(); // call displayName
}
sayMyName(); // call sayMyName
Enter fullscreen mode Exit fullscreen mode

example courtesy of Mozilla

You can run this in your Console too! On Chrome you can hit ⌘-Option-J (Ctrl-Shift-J on Windows) and copy pasta the code above. Feel free to have it say your name instead!

What are closures?

Closures are similar to lexical scoping, but provide us different benefits. Above, we called displayName immediately. However, in Javascript, functions are considered as first class objects. All this means is that we can treat functions as objects (an object is a complex topic, but it's easiest to think of as an entity, like a person or a car). Lets modify our example above a bit: Key Terms:

  • return: a return statement is the final line of code in a function. It basically returns the computation done
function sayMyNameClosure(name) {
  // we don't need our local variable anymore since we're passing name as an argument
  function displayName() { // displayName() is the inner function, a closure
    console.log(`Hi ${name}!`);
  }
  return displayName; // return displayName
}

let sayBram = sayMyNameClosure('Bram');
let sayBradPitt = sayMyNameClosure('Brad Pitt');

sayBram(); // call sayBram
sayBradPitt(); // call sayBradPitt
Enter fullscreen mode Exit fullscreen mode

What's happening here is that we're setting up two separate lexical scopes. These scopes are unique, and both have a different idea of what name evaluates to. In sayBram name = Bram, but in sayBradPitt name = Brad Pitt. Feel free to try these out in your console!

Fight Club

First rule of closures: don't talk about closures

What does this have to do with improv??

I agree, that's enough code, let's focus on comedy here. In improv comedy, the structure usually goes as follows: the audience gives your team a word or a phrase, you spend 20-30 seconds coming up with scenes about it, and then you go wild. The great thing about improv is that it's all based on Yes, and, which means that everything your team members say is "true" for the scene. Okay, so let's say the word is typewriter. I might come up with a scene about how I work at a 1950's news company, Mad Men style. My partner and I would act the scene, and pay attention to which bits get laughs. We then would store those away with the character for later.

Example:

Scene 1: (Me and one other person) I'm a distraught house husband whose novels aren't taking off because they're really bad. However, my wife doesn't want to shatter my confidence so she tries to stifle her laughter as she reads my book.

Scene 2: (Two other people) A completely different timeline where typewriters are falling from the sky, causing mass hysteria. Kind of like Fahrenheit 451 meets dinosaur asteroid extinction.

Scene 3: (Me and someone from scene 2) We both narrow in on what went well with the audience the last two scenes and really send those jokes to the moon (as in, we make them even bigger and crazier) What we're doing here is lexical scoping! We're remembering who our characters were and what they did, and then were invoking them later, like tellFunnyJokeFromEarlier(). I won't act as someone else's character and use their jokes, and they won't use mine!

Rule of Three

I want to close this out discussing the rule of three. The rule of three basically states that jokes are really funny if you use them three times. The rule of three also applies to photography in the Rule of Thirds (another post for another day), and slogans like Stop, Drop and Roll. Three is just a really memorable number. So using what we've learned above we can write improv comedy as code like this:

function funnyJoke(person) { // pass in our person into the scope
    function tellJoke(joke) { // pass in joke when we call funnyJoke
        console.log(${person}: ${joke});
    }
    return tellJoke;
}

const bramJoke = funnyJoke('Bram');
const bradJoke = funnyJoke('Brad Pitt');

bramJoke('What\'s the deal with airline food?'); // first time
bradJoke('Q: What is Homer Simpson\'s favorite ice cream? \nA: Chocolate-chip cookie d\'oh!')
bramJoke('What\'s the deal with airline food?'); // second time
bradJoke('Q: Why is the math book always upset?\nA: Because it has a lot of problems.')
bramJoke('What\'s the deal with airline food?'); // third time -- audience dies of laughter
Enter fullscreen mode Exit fullscreen mode

Top comments (0)