1

I have heard that since JavaScript would hoist all the local variables to the front of the function, it is better if the programmer just hoist it himself or herself, so that everything is seen as how things would actually occur.

Example is:

var i, result = [];

which is to declare all local variables at the beginning of the function.

But I also saw in some classical code, such as in React JS's source code that it would do

for (var i = 0; i < ...; i++) { ... }

that is, declaring it when i is first used -- so that if this line is removed, the declaration will be removed together.

If we hoist it manually, there is a danger that when that loop is removed, the var i; is still left there. (although linting probably would catch it).

I also have seen weird look from interviewers when I hoists all the variables to the front of the function definition too.

Should we hoist all variables to the front? Or what if we hoist all variables except the temporary variables such as i and j?

nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 1
    At some point we'll be able to use `let` everywhere, maybe you already can. – RemcoGerlich Apr 14 '17 at 18:03
  • Given your functions shouldn't have more than a few lines it really doesn't matter. – plalx Apr 14 '17 at 18:12
  • @plalx Ever write an AngularJS controller? Or a complex object/class definition? – mhodges Apr 14 '17 at 18:36
  • @mhodges I built many AngularJS enterprise applications. Controllers aren't different from the rest. – plalx Apr 14 '17 at 21:23
  • @plalx I'd love to see your "no more than a few lines" controllers for enterprise applications. The bloated controller issue was one of the main reasons Angular2 ditched the entire controller concept. – mhodges Apr 14 '17 at 21:28
  • @mhodges Ng1 or Ng2 has nothing to do with it IMO. People writing bloated controllers in Ng1 will write bloated components in Ng2. Bloated stand for too many responsibilities, which has little to do with coding style. I could have all the bloat logic in a single function or factored into many small functions, it wouldn't change the fact that the controller or component does too much. Still, what I'm saying is that functions should generally have a single responsibility and be very small and that can be done in any framework. – plalx Apr 15 '17 at 03:07
  • Given such functions, you'd never have to scroll to see the variable declarations, whether they are all at the top of the function or not. The only special case are modules (IIFEs) which tends to be very large. – plalx Apr 15 '17 at 03:08

4 Answers4

2

Limiting the exposure of variables to the context they are useful in can be an extremely valuable auto-documentation strategy: It lets the next person who picks up the code know where variables are and are not relevant. So no, don't "hoist" because the JavaScript engine is internally doing it

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • I forgot where I read about it that we should hoist it... maybe the JS Definitive Guide or JS The Good Parts... but I have mentioned this rule in interviews, so I hope I didn't get disqualified for this – nonopolarity Apr 14 '17 at 18:32
1

I also have seen weird look from interviewers when I hoists all the variables to the front of the function definition too.

Should we hoist all variables to the front? Or what if we hoist all variables except the temporary variables such as i and j?

There are basically two schools of thought on this. One is to declare all of your variables in one place, usually at the top of whatever they are scoped to (which is the function in which they are defined, if you are using the var keyword). The other school of thought is to declare variables as closely as you can to where they are used. They both have valid arguments, and honestly is a matter of opinion and preference.

Before getting into let and ES6, I will first talk about the two arguments above.

Declaring at the top of the scope

The advantages of this are that you always know where your variable declarations are, and you are always aware of the parent scope. Immediately when looking at the function, you can determine what variables are used throughout, and you can trace where they are used from there.

The disadvantages of this are that, depending on your code structure, it may be 100 lines from where a variable is declared and where it is used, which can make debugging a bit of a challenge sometimes and requires you to carefully trace the variable you think you are using in the function, because it may not always be the one declared at the top, especially in the case of shadowing.

Declaring as close in proximity to where the variables are used

The advantages of this are that when trying to determine variable scoping and shadowing, it is very easy to determine what version of the variable you are working with (especially with nested functions). The other advantage is code-cleanup. If you remove a function or a loop and there is a variable declaration right above it, it is usually a pretty good reminder to remove that variable declaration as well because it will not be needed anymore. Obviously that's not always the case, but many times it is. When declaring at the top, variables can get lost in a sea of declarations and be left unused - yeah a linter can catch that, so it may be a moot point, but it's a point nonetheless.

The disadvantages of this are the exact opposite of the advantages of declaring at the top. If you are looking to see what variable names / identifiers are used in a given scope, you kind of have to go digging. CTRL + F is your friend, but it is faster to look at a list that is all in one place.

Now what about let??

Again, there are two schools of thought on this: one is "let is the new var" and the other is that "let simply allows us to do syntactically what we already were doing stylistically"

For example, take this code:

var result;
for (var i = 1; i <= 10; i++) {
   result = 2 * i;
   console.log(result);
}

Vs.

for (var i = 1; i <= 10; i++) {
   var result = 2 * i;
   console.log(result);
}

Now, from the compiler's perspective, they are identical. However, the second version (stylistically) is telling the reader of the code "The result variable is only being used inside this for loop", whereas the first version is ambiguous to the reader as to what may or may not be happening to the result variable later on in the code. These are stylistic and conventions that developers unspokenly adhere to in order to convey intent of the code. And that is the argument of the second school of thought - let simply allows us to do, syntactically, what we are already doing stylistically.

Community
  • 1
  • 1
mhodges
  • 10,938
  • 2
  • 28
  • 46
0

This might have been relevant a few years back.

Now, you should use ES5 or later, which introduced the let keyword, which solves the hoisting issue. let declared variables are block-scoped and will not be hoisted.

Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
  • `for (let i = 1; i <= 5; i++) { ... }` that looks weird... but that's how it is I suppose – nonopolarity Apr 14 '17 at 18:30
  • Yup - that's the better style in modern Javascript. Takes a little getting used to, but you should almost always prefer using `let` or `const` over `var. – Kenan Banks Apr 14 '17 at 18:31
  • And yes, IE is way behind. Use a transpiler (e.g. babel, closure compiler, typescript, etc) if it's feasible for your team. – Kenan Banks Apr 14 '17 at 18:31
  • @Triptych Why'd we have to bring `const` into this.. lol it is probably one of the single worst features of ES6 simply due to its ambiguous and counter-intuitive connotations. – mhodges Apr 14 '17 at 18:43
  • It pretty much does what I'd expect. Don't think I've ever been surprised by how it works. What's confusing about it to you? – Kenan Banks Apr 14 '17 at 18:44
  • @Triptych In most other languages, it infers certain characteristics (usually immutability) on the **value**. However, in JavaScript, it has nothing to do with the value, and everything to do with the variable containing the value. Connotatively, if something is constant, that means it doesn't change - however, JS `const` **values** are fully subject to change - you just can't reassign the variable. That is a key distinction from most other languages, which is why it can create a lot of confusion. – mhodges Apr 14 '17 at 20:00
  • I disagree. A const pointer in C for instance (e.g. `char* const s`) simply means the pointer always points to the same location in memory. The contents of that memory are free to change at any time. It doesn't really make sense to say the value 2 can't change. That's always true. There's a different between mutability of values and constant names. One typically doesn't affect the other. In Javascript, arrays and objects are always mutable, and everything else isn't. Seems reasonable to me. – Kenan Banks Apr 14 '17 at 20:26
  • 1
    @Triptych I guess that I would argue that setting a `const` equal to an array or an object that you do not want to be immutable defeats the purpose. I have seen so many people wondering why their const array data is getting changed when they perform certain array operations (i.e. `pop`, `push`, `splice`, etc.). I agree with you, it is a misunderstanding of how the feature works, but why would you even introduce something so ambiguous into your code base? Declaring an array or object as `const` tells the reader next to nothing, and more often than not leads to wrong assumptions. – mhodges Apr 14 '17 at 21:53
  • 1
    I do see code doing that: using `const` and change the object's internal properties freely. So if more and more code do it this way, we will get a feel for `const` only means the reference doesn't change, but the object can change however it wants – nonopolarity Apr 20 '17 at 00:07
0

I guess sometimes it makes sense to use strict mode

"use strict";

which can be implemented for the whole file or for a function

function strictFunction() {
   "use strict";
    var y = 3.14;   // This is ok
        x = 2.414; // This will cause error
}

which can help writing more secure code by avoiding global variables. So technically it depends how your for loop is being use. Reference "use strict";

You can also use let instead or var as suggested by @RemcoGerlich to scope your variables

Vinod Srivastav
  • 3,644
  • 1
  • 27
  • 40