const keyword I spoke about before.
.freeze() prevents changes inside the object.
const prevents changing what a variable points to. I’ve demonstrated arrow functions in previous lessons, but here’s a quick recap. The first two examples here use the
function keyword, either creating a named function in the global namespace or assigning it to the
add() variable in the local context.
This third example is the arrow function shortcut. There are some subtle differences with scoping and the
this keyword, which I’ll describe later when I talk about language quirks.
But otherwise, this is equivalent to the above two. Using the arrow (
=>) means you no longer need the
function keyword and the return value is implicit.
01:15 Arrow function shortcuts typically get used for anonymous expressions like lambdas in Python but unlike lambdas they could be multiline and have side effects, like in this fourth example.
01:27 Because the curly brackets are used to define the code block of the function, if you want to return an object from an arrow function, you need to wrap it in parentheses.
This last example returns an object that has a key called
result, whose value is
a + b. So that the parser doesn’t get confused, this is wrapped in parentheses.
Why am I bringing up this tangent? Well, those labels are defined with a name and a colon. Without the parentheses in the fifth example, the curly brackets are seen as the arrow function definition and the
result: is seen as a label.
Let’s go to the REPL and see these in action. First, I will define a function called
greet() with a default value for the
greet() with a value.
02:45 And then without one. Here’s a more complicated example.
This method returns the array of the third parameter with the first and second parameter pushed inside of it. If
c isn’t given, the array returned starts out empty before
b are pushed inside. And if
b isn’t given, it is set to the value of
a + 1.
Calling it with
1 means the empty array from
c is populated with
1 + 1.
Here it is again with a different value. Note that the array of
c has no continuity between calls. It gets reset to empty.
If I pass in an array for the value of
c, then the
b arguments are pushed on the end of it. Unlike Python, there is no named calling.
It treats it as the second argument, and you will end up with the real
c being an empty array and the value of
41 and the value of
b being the array
[9, 8, 7].
SyntaxError, a warning, something—anything!
05:04 How about functions with a variable number of arguments?
...). Here, I’ve defined a function that can take any number of arguments.
I then sum them up using the
.reduce() function, then take the average. If nothing is passed in, the average is arbitrarily chosen as
The rest operator causes the
numbers argument to work like an array. Let’s try calling it a few times.
05:56 Looks all average-y. Good work. There’s one more place that the rest operator can be used, which is to access the remaining parts of an array. Flashback to some fruit.
This array was composed using the rest operator, acting on the
06:23 The end value is a composed result.
raise instead. Here, the
fruits array contains three items:
'orange'. On the second line, the array containing variables
c are assigned to the
c now contain
age now contain the values of the attributes of the
This has nothing to do with the Python
with statement and is completely different. That’s unfortunate for those of us who use both languages.
Support is pretty much across-the-board now but if you’re coding for older browsers, you may get into trouble. Anyhow, if you’re in sloppy mode—that’s what the cool kids term the opposite of strict—the
with keyword is like a code block based destructuring.
In the example here,
with person makes variables available in the block named for each of the attributes of
person. I wouldn’t recommend using this feature, it’s not very common anymore, but thought it should be explained in case you came across it.
When you use a
for loop to get the components of a list in Python, you’re iterating over it. The
list object conforms to the iterator protocol.
08:36 A generator is a special kind of function that returns a suspended generator object. Yeah, I did it again. Another definition based on its definition. Think of a function that returns a list. That function has to create the entire list in memory, which it then returns. A generator is a way around that.
Instead of returning the whole list, it returns a promise about the list. Iterators then say to the generator, “Give me the next item in the sequence,” and the suspended generator object complies. The
yield keyword in Python is what does this magic trick of suspending the generator and returning the value.
I’m going to write a quick generator function that returns random values between
100. First off, I’ll need to import
randint from the
09:37 Declaring a generator function in Python is no different than any other.
The key part of this is the
yield indicates that this is a generator function. When the function is called, instead of doing anything, it will return an iterable generator object.
When the object is iterated on, the
yield keyword is what returns the next value in the sequence. In this case, it will be a random integer. Now I’ll call it the function.
x contains a generator object. To get the next item in the sequence from the generator, I could put this in a
for loop, but all that loop actually does is use the built-in function
next(), so I’ll call that directly here. And again, and again, one more time.
This function stops the
while loop after
count iterations. When I called the function,
3, so I got three random integers in sequence.
The fourth iteration has the function leave the
while loop and return. When an active generator returns, it throws a
StopIteration exception signaling that it is done. If this were inside of a
for loop, the
for loop would see this exception and leave the loop.
Since I’m not in a
for loop, I see the exception. Any completion of the generator function will cause the same result. If you need to short circuit your iterator, you can use
return in your function. That’s the Python way.
*) here tells the parser that it is a generator.
There’s a local variable called
sent that is used to track the number of times the function has yielded. The
yield statement sends out the next item in the sequence and there’s a
while loop to do it
count number of times. There’s no
random() function that returns a float.
12:12 Just like Python, you call the function and get back a generator object.
12:33 Let’s agree as friends to never mention that I did that, okay? Moving on. Notice that what comes back isn’t the random value, but an object. The object has two attributes, the value and a Boolean to indicate whether the iterator is finished.
The Python way of dealing with this feels less clunky to me. Okay, that’s better. The universe is in balance again. Calling
.next() another time, and again, and the last time. Here, you see the empty value and the
done flag set to
True, the equivalent of the
StopIteration exception in the Python world.
How about if you want your generator to call a generator? You can do that as well. Python uses the
yield from keyword to achieve this. on the left-hand side, more Python.
This is similar to the code from before, but this time I yield from a list of random integers instead. Calling the generator with a count of
.next(). Hm, what happened here? The count was
1. Well, the count was
1, but the
yield from is like yielding in a loop.
14:00 As there were three things in the list being yielded from, there will be three results.
And there’s the expected
*) to indicate yielding from a generator. I’d be remiss if I didn’t complain about this being painful for C programmers, but I think I did that already.
The rest of it is the same. Call the function, get a suspended object,
.next() the object,
.next() the object,
.next() the object, and the last time with the
done flag set to
Here, I called
.next() on the suspended object, but passing in a parameter at this point the parameter does nothing. What you’re seeing is the result of the
yield from the function.
On the second call, the parameter is getting used. Think of this as the
yield statement returning the parameter that you passed into the call to
'pong' is sent back from the yield, and as there was only the one
yield, the next item in the sequence is the end. The parameter that was passed back from the call to
.next() is then returned.
The result of the next call includes
'pong' and the
done flag set to
You’re definitely on the part of the map that says “Thar be dragons!” To create a function that runs asynchronously, you declare it with the
16:28 When such a function is called, instead of getting the result, you get a promise object. This is a similar concept to the generator. It is a proxy to the result.
You resolve such a promise with the
await keyword. Why would you do this? Well, if the
greet() function here were doing something terribly complicated like waiting for a result from a server, you could take advantage of that time and do a whole bunch of computation between the promise and the
When you’re finally at a point where you absolutely must have the response back from the server, then you do the
await. If the response had come back, you’d get it immediately. If it hadn’t, you would block until it returned.
for loop inside of the
greet() function, it would get run when the function was promised, not in a separate thread.
You’d end up with some very synchronous-looking asynchronous code. To make matters worse, async functions have to be chained. If the
greet() function called another function that wasn’t asynchronous, you could get some odd results.
Array objects have an iterator method on them called
.forEach(). It isn’t built with async.
17:52 If you forget this and call one inside of your async function, it will mess up your async function. No, I didn’t say it would give you an error. It just messes with your results.
Become a Member to join the conversation.