Transcript from the "Cheating Lexical Scope: eval" Lesson
[00:00:20] Well, the eval keyword takes any given string and it treats the string contents as if that had been code that existed at that point in the compilation. So when we compile this code, we would see that the function foo, defined from lines three through six, we would see that that function does not have a variable called bar in it.
[00:00:41] Everybody would agree with that, right? There's no variable called bar in it. So when I execute line five, I would expect what? I would expect for it to go out to the global scope and get this value bar here. But because we choose to pass in a variable declaration in the form of a string and eval will run it on line four, it cheats it and it pretends that that line of code had existed at compile time.
[00:01:04] So in a sense what it does is it modifies the existing lexical scope of foo to add a new declaration to it at runtime. Does everybody see how that works? It cheated by modifying what would have otherwise been a write time author time lexical decision, it cheated and modified it at runtime.
[00:01:44] Because it has to assume the worst case, that at runtime your going to invalidate all of those assumptions. So just simply doesn't do the optimizations at all. And when it doesn't do those optimizations at lexical write time, it makes your code run slower at runtime just by virtue of having the eval present.
[00:02:02] Even if you're not actually modifying it, just by virtue of having it present, it has to disable some of those optimizations. Can it do still some optimizations? Yes, maybe. But by virtue of putting eval in your code, your code will tend to run slower. Of all the arguments against the eval keyword, to me that's the one unequivocal argument against the eval is that it would make your code run slower.
[00:02:27] Now there is a nice silver lining to this, that as of strict mode, when you put a variable inside of an eval like this, it actually creates a whole new scope just for the eval statement. So yes it's creating a new scope but it's not modifying an existing one, which allows the engine to continue to do its optimization.
[00:02:45] So technically the strict mode code, though it might break your assumption about how things work, the strict mode code is technically gonna run faster. That's actually most of the reason why they put stuff into strict mode. It wasn't just about making better code, it was about making more optimizable code.
[00:03:04] Okay, I would suggest to you never ever use the eval statement. Now there are some people that argue that eval is still a useful mechanism and that we shouldn't throw it out and that it should still be available to people. So this is the way I teach it.
[00:03:18] And everybody has their own different opinions on it. But the way that I teach it is if you have to ask whether or not it's okay to use the eval keyword, the answer is no. If you happen to be that one or couple of people in the world that's in that one or a couple of niche circumstances where the eval key word is necessary, you already know it and you're not gonna ask anybody.
[00:03:41] So I will provide you this public service announcement. I will provide you with this public service. From here on out, if you ever find yourself asking, should I use the eval keyword or not, just give me a call, give me a tweet or something, and I'll remind you no you shouldn't use it.
[00:03:54] This is the service that I provide to all my students, okay? So if you have to ask, don't use it.
>> Speaker 2: What about the string set timeout syntax?
>> Kyle Simpson: It's the exact same thing. It uses the eval mechanism underneath the covers. It does the exact same thing. [COUGH] Okay, so don't use eval.
[00:04:13] Now I would be remiss if I didn't give you some clues to what might possibly be one of those niche cases. Remember, I said to you I wrote a templating engine? What dose the templating engine do? It takes other code and it produces new code from the other code.
[00:04:41] The other way to do it is to eval it or put a function constructor on it. I actually use the function constructor because it's better than eval. But the templating engine is one of those really small niche cases where you might need it. Maybe you need to do some kind of weird ES6 feature testing thing inside of an eval.
[00:04:59] There are really crazy corner niche cases. But the vast majority of you are never, ever, ever, ever, ever gonna need to use eval. So if you find yourself feeling like you're in one of those cases, you're probably not. And you'll know it if you are. Does that make sense?
[00:05:14] Okay, now eval is one of the ways that we cheat. Turns out there's an even worse way that we can cheat, like SQL scope. There's a lot of different ways that people teach this mechanism. But anybody ever heard of the with keyword? So yeah.
>> Speaker 3: Sorry, we had a question on [CROSSTALK] set timeout.
>> Kyle Simpson: Okay.
>> Speaker 3: Does that mean we should avoid using that as well?
>> Kyle Simpson: You should avoid using set timeout with the string syntax. So you should never do set timeout, quote and then calling a function. Because that's code that will get eval-ed at run time. I use set timeouts all the time where you give it a function reference.
[00:05:48] That's a totally safe way. But don't use the string syntax as the parameter of set timeout.
>> Speaker 3: Got it, thank you.
>> Kyle Simpson: Okay, the with keyword. Now there's a lot of different ways to explain it. Let me just kind of illustrate to you why the with keyword can be useful, what was the reasoning behind inventing the with keyword.
[00:06:08] I've got an object called obj there on line one. He's got some properties like a, b and c, these values. And then I've got code like lines seven and eight where I want to do a bunch of operations with those properties. So you see that I'm kind of verbosely repeating the obj dot reference over and over and over again.
[00:06:24] And that's really kind of annoying, all right? So what if there was a way to sort of shorthand that? And it turns out the with keyword is how we can shorthand that. We can say with obj, and now inside of that block we assume that all of those variables are actually meaning to represent properties of our object.
[00:06:40] So we can just say a equals b plus c and so forth. And so we kind of shorthand our way through it. People that do code golfing competitions and JS1k, they use the with keyword a lot. So it can make shorter code. It certainly can make it nice, easier code.
[00:06:55] There are some problems with the with keyword though. The first problem, kind of the major one that people point out, is that we see line 13. Look what's happening there. I'm basically saying d equals 3, what's my intent? My intent clearly is I want to create a d property on the obj object, right?
[00:07:11] But that's not how it works, that's not what it does. Guess what actually happens when I run line 13.
>> Speaker 2: Hey, object, you got a reference to [CROSSTALK]
>> Kyle Simpson: It says, hey object you got a reference because it's actually treating this with statement as a lexical scope. And it's gonna behave by the exact same rules of lexical scope that we already learned.
[00:07:32] So it's gonna say, hey scope of with statement obj, do you have a variable called d? And what's his answer gonna be? Go fish, so he's gonna go to the outer scope, which in this case is the global, and he's gonna say, hey global scope I've got an LHS reference for a variable called d, ever heard of him?
[00:07:48] And what's the answer gonna be? Yeah, I just made one for you. So I created autoglobals. Here I didn't want to create an autoglobal. But because it didn't already exist. When I say on line, this is a typo. That should've been c equals b minus a. But when I say it on line 11, when I say a, well I'm assigning the value in.
[00:08:09] So the property already exists. And the lexical lookup works, and it works correctly. But when I make a reference like line 13, that variable doesn't exist yet. And it creates it out on the outer scope. So that's reason enough to avoid the with statement, is that easy foot gun of creating autoglobals.
[00:08:29] But that's not even the worst thing. Because I'd say that the with keyword is even more evil than eval. And the reason for that is because where the eval keyword was modifying an existing lexical scope, the with keyword at runtime is creating a whole new lexical scope at runtime.
[00:08:47] So it's doing even more to invalidate your assumptions at write time of what your scoping rules look like. And guess what happens when the compiler sees a with keyword in your code. It has to assume the worst, and it disables many of its optimizations. So in the same way that I'd say with eval you should avoid it, you should avoid the with keyword.
[00:09:05] And in fact, as of strict mode the with keyword is completely disallowed altogether.