5 ms·
This is one of the few posts about javascript that I've encountered that sees hoisting as a good thing. I like `let`.
by gamesbrainiac 12y ago
This is one of the few posts about javascript that I've encountered that sees hoisting as a good thing. I like `let`.
- quarterto 12y agoHave you read the linked article about typeof? Normally, it's safe to do typeof possiblyUndeclaredVariable, but if later in the function you do let possiblyUndeclaredVariable it starts the scope defined as "uninitialized", which causes typeof to throw.
- umurkontaci 12y agoWell that's perfectly normal in a properly scoped language.
- virmundi 12y agoWhat you have to keep in mind is that JavaScript is not "a properly scoped language". Pretending that it is will cause you to miss key aspects of how the tool works. This helps no one, including you. Please, for as crappy as the language might feel, approach the language on its own terms.
- umurkontaci 12y agoFunction scopes and variable hoisting was not the best parts of JS anyway. let brings lexical scope into the game, which I think is a great progress. And you cannot expect a variable to be defined outside of its lexical scope. That's not any different that trying to access a variable outside of a function that is defined in. If people were abusing variable hoisting in some way, they can continue to do so, by not using `let`.
- makomk 12y agoIf I'm following the blog post correctly, let does have effects outside of its lexical scope: it effectively makes the variable even more undefined than a totally non-existent variable. That is, the following code will not throw anything: // x has not been defined or initialized anywhere console.log(typeof x) However, if you add a let statement after it like so: // x has not been defined or initialized here console.log(typeof x) let x = "foo"; typeof will fail with an exception, because the let statement changes x from an undefined variable to a new state that isn't even undefined anymore.
- umurkontaci 12y agoI understand, but I believe this still happens only within the lexical scope where the variable has been defined with let. TBH, It doesn't bother me at all. I think I can even go ahead and say the latter makes much more sense. Using the former one is abusing the weaknesses of the language that has come along with it throughout its history. We have been whining about the bad parts of JavaScript for a long, long time and I think these changes are for the better for all of us.
- TeMPOraL 12y ago> I understand, but I believe this still happens only within the lexical scope where the variable has been defined with let. Doesn't let itself introduce a new, implicit, scope? Here it seems let acts on things outside its own scope, which seems at least ugly.
- ajanuary 12y agoIt's not having an effect outside of its lexical scope. You introduce the let into the same lexical scope as the console.log. It will also throw an exception every single time. So unless you're adding a variable, and then never testing the code path that hits the new line, you're probably going to catch it pretty early.
- TeMPOraL 12y agoWell, but doesn't let itself create a new implicit scope, from the point of the let statement to the end of the scope the statement is in? It seems to me that here let is indeed acting on things outside of lets own implicit lexical scope.
- jrochkind1 12y ago> And you cannot expect a variable to be defined outside of its lexical scope. Okay, but since `typeof x` can return "undefined", I would expect it to return `undefined` if x is no defined. Now, sometimes `typeof x` returns `undefined` if x is not defined, but other times it raises if x is no defined. That's the issue. I too predict this is going to give people a lot of trouble. We will see.
- TeMPOraL 12y agoAnd the worst thing is, introducing a let variable affects code outside of the implicit lexical scope created by that let. The switch from "undefined" to "more undefined" happens one scope above. Even if it doesn't create much of a trouble for people, it feels like a very ugly design.
- ajanuary 12y agotypeof isn't raising the exception, the runtime is raising it before typeof is even evaluated.
- jrochkind1 12y agoI understand the implementation details, but the fact remains that previously you could call `typeof something` for any `something` at all, and it would never throw, ever. So you could use it as a way to check if a variable was defined. Now, sometimes it will throw. I mean, come on, you really don't see anything confusing in the fact that there are now two kinds of `undefined`, one kind you can call `typeof x` and it returns `undefined`, but another kind of undefined where you can't mention x at all without a throw? Like, if you can't mention undefined variables without getting a throw, how come `typeof` sometimes returns `undefined`? Ah, because some "undefined" variables you can do that with, but not others? So I guess there is more than one "kind" of "undefined" now? This is not confusing?
- ajanuary 12y ago> Now, sometimes it will throw. No, typeof /isn't/ throwing. let x = 1; function some_random_function(y) { } (function() { some_random_function(x); let x = 2; })(); This will throw the same exception for exactly the same reason. You're using a variable defined using "let" before the variable definition. Sod all to do with typeof. I don't see it as massively confusing that a variable declared one way behaves differently to a variable declared another way. That's the whole point of having a new way of declaring a variable. Why isn't everyone up in arms about how confusing it is that it behaves differently here? (function() { var x = 1; if (true) { var x = 10; } console.log(x); // Will print 10 })(); (function() { let x = 1; if (true) { let x = 10; } console.log(x); // Will print 1 })(); Oh no, if I use "let" it behaves differently to "var"! Its not like its throwing on unexpected data, its throwing because the program isn't constructed properly. This is the same as just about every other language. Are you really saying we shouldn't make improvements to the language because then it would behave differently to the old, poorly designed features we're trying to deprecate? [edit] You still can use typeof to check if something is defined without throwing on spurious inputs. The only time the code will throw is if you make changes to further down in the lexical scope. And guess what - whether you do that with var or with let you've changed the argument of typeof to refer to a different variable. Except with var it will likely silently fail in a hard to track down way, while with let it will error in an obvious place. let data; function sanitizeData() { if (typeof data === 'undefined') { // data not yet set return; } // sanitize data in place } No matter what you put in data, "typeof data" is never going to throw an exception. The only way to get it to throw an exception is to change sanitizeData to add a variable shadowing "data" from the parent scope. let data; function sanitizeData() { if (typeof data === 'undefined') { // data not yet set return; } // sanitize data in place var data = ...; // sanitize data in place } If I use var, sanitizeData doesn't do anything and I spent a while hunting the issue down. let data; function sanitizeData() { if (typeof data === 'undefined') { // data not yet set return; } // sanitize data in place let data = ...; // sanitize data in place } If I use let, sanitizeData throws as soon as it's called and I can track down the issue much quicker. The only time "typeof throws an exception" is if you add a let statement later in the lexical scope in a place where if you added a var statement, it would completely change the behaviour of your code in a way you almost certainly didn't want it to.
- the8472 12y ago>it's safe to do typeof possiblyUndeclaredVariable What would be the usecase of typeof'ing something undeclared in a block scope and then declaring the let further down? Even more so with strict mode which does't really allow you to use undeclared variables anyway.
- ajanuary 12y agoThat part of the article isn't particularly clear. The intended behavior of let is great. The unintended behavior - that it can cause typeof to fail - is bad.
- deleted 12y ago[deleted]
- gildas 12y agoHoisting is great thing, it is really helpful to improve readability when doing asynchronous function calls. function a(){ setTimeout(b, 1000); } function b() { setTimeout(c, 1000); } function c() { }
- kaoD 12y agoIf I'm not mistaken that's not hoisting, since that code will work as long as a() is called after b is declared regardless of the hoisting. Keep in mind b is only accessed when a() is actually executed, not when it's declared! Hoisting works like this: a(); function a() { console.log("FOO"); } Which might or might not be more readable, depending on your tastes.
- deleted 12y ago[deleted]
- gildas 12y agoYou're right, my example was not very good indeed.
- bananaoomarang 12y agoI guess the argument here is that let adds inconsistency? ie: var statements are hoisted and let statements aren't. It's a double edged sword: On the wone hand it can be used to improve readability, but it also adds complexity/more to bear in mind.