Important JavaScript Concepts


1. JavaScript Statements and Expressions

The MDN documentation defines JavaScript expressions as any valid unit of code that resolves to a value.

a = 1;
3 + 4;

The first expression has value 1 which is then assigned to variable a while the second has value 7 which is not assigned to anything.

Since expressions evaluate to values (numbers, strings, functions etc), they can be substituted anywhere these values are expected. Programmers just have to ensure expressions resolve to expected values because of JavaScript’s weak typing.

Consider the following simple statement:

var x = "statement";

This is a statement and not an expression. Statements do something while expressions evaluate to values.

Dr. Axel has an excellent post which differentiates both: “you can use expressions where statements are expected (these are called expression statements) however you cannot use a statement where an expression (i.e. something that evaluates to a value) is expected”.

To simplify; you cannot use the statement above as a condition for an if branch (which expects an expression or value).

2. JavaScript Variable Scope

Scope determines the lifetime of variables and where they can be used. Most programming languages have block scope, i.e. variables only exist within enclosing blocks (usually delimited by braces). However, JavaScript has other ideas… Check the code snippet below.

function JSBlockScope() {
    var noBlockScope = "BlockScope";
    if(true) {
        var noBlockScope = "FuncScope";
    }
    console.log(noBlockScope);
};

JSBlockScope();
//logs FuncScope

The output is “FuncScope”! Surprised? Block scope implies that declarations inside blocks do not overwrite external variables. JavaScript has function scope and consequently noBlockScope gets overwritten to ‘FuncScope’.

Function scope also means that variables declared inside functions are only available inside those functions, once the function exits, the variables are inaccessible anymore (well, unless you use closures…).

function scopeCheck() {
    var functionScope = "inside Func";
    console.log(functionScope);
};

scopeCheck();
// logs inside Func

console.log(functionScope);
// ReferenceError: functionScope is
// not defined

The functionScope variable defined inside the scopeCheck function only exists inside the body of the function.

Variables are first looked up in the current scope (i.e. the enclosing function), if not found, then the interpreter continues walking up enclosing scopes until it gets to the global scope. If the variable is not defined still; then the well-known “ReferenceError: variable is not defined” error occurs.

3. Hoisting

JavaScript has this weird but fascinating concept called hoisting. All variable declarations are hoisted – every variable gets declared immediately even though their values might not be set immediately.

function hoisting() {
    console.log(hoistedVar);
    var hoistedVar = "hoisted!";
    console.log(hoistedVar);
}

hoisting();
//logs undefined
//hoisted!

Explanation

Confused? Well what happens is that all declarations are hoisted to the top before any code execution begins. The above code is totally similar to the one below:

function hoisting() {
    var hoistedVar; //undefined
    console.log(hoistedVar);
    hoistedVar = "hoisted!";
    console.log(hoistedVar);
}

hoisting();
// logs undefined
// logs hoisted!

The log statements show ‘undefined’ since this is the default value for uninitialized JavaScript variables. If they weren’t hoisted, the interpreter would have thrown a ReferenceError. 

Hoisting also applies to functions (JavaScript functions are values afterall…) however there is a subtle difference between function declarations and expressions. Function declarations get hoisted to the top and are immediately available within the scope while function expressions are only declared and not hoisted (much like the same case for variables above). 

function isFunc(fn) {
    var isFn = (typeof fn === 'function');
    console.log(isFn);
}

function isUndef(fn) {
    var ntDef = (typeof fn === 'undefined');
    console.log(ntDef);
}

function funcHoisting() {
    isUndef(declaredFn); //false
    isUndef(hoistedFn);  //true

    function declaredFn () {};
    var hoistedFn = function () {};

    isFunc(declaredFn); //true
    isFunc(hoistedFn);  //true
}

funcHoisting();

Declaring variables at the top of functions helps to avoid hoisting surprises.

Conclusion

I was going to write about function expressions vs declarations, however I believe these three JavaScript concepts would significantly make it easier to understand that topic. Insha Allaah I’ll publish the function expression vs declaration post next.

Meanwhile, here are some other posts you might like:

1. The JavaScript Function
2. A peek into JavaScript’s Array.prototype.map and jQuery.map
3. Programming Language Type Systems I

27 thoughts on “Important JavaScript Concepts

  1. Your make this statement, “Consider the following simple console logging statement:” but your example doesn’t include console.log() at all (probably as a result of the editing performed after Peter’s comment of March 10th).

    Later you make this statement, “To simplify; you cannot put the console.log statement inside the body of an if branch (which expects an expression or value).” Your phrasing is wrong. The “body” of the if statement is everything other than the conditional test expression, ie. the true and false blocks. Instead of “inside the body” it would be better to say “inside the test expression” or “inside the conditional expression”.

    Your code example of “funcHoisting()” is wrong. The last two lines are identical and you probably meant to call the function with different parameters. And you say, “Function declarations get hoisted to the top and are immediately available within the scope while function expressions are only declared and not hoisted (much like the same case for variables above).” I would argue that it’s not “much like” variables, but “is exactly the same as” because they ARE exactly the same — they’re both variables.

    Otherwise, it’s a good article. I remember when I was learning JS and I couldn’t believe what I was reading in the ECMA standards documentation regarding scope and hoisting!

    Like

    1. Thanks Azhrei for spotting the errors and pointing them out, I updated the article and fixed those issues.

      You are right about functions being variables however there is a subtle difference. While still remaining variables,
      function declarations get hoisted and are immediately available to use in a scope while variables are hoisted but
      can’t be used until the interpreter exectes their assignment line.

      Thanks for the excellent feedback! JavaScript is surely perplexing at times!! :)

      Like

  2. Not to hate on dynamic languages. But the probability of error due to this unbridled “freedom” (hoisting & scoping) always come to bite especially in a large codebase.

    See for example.
    console.log(hoistedVar);
    var hoistedVar = “hoisted!”;

    This will simply not compile in static environment. Hopefully such errors can be caught by unit tests and even highlighted by intelligent IDEs.

    Admittedly JS is the future. Good to read posts like this that expose JS gotchas.

    Like

    1. Jazakallaahu khayran for taking time to read and comment! Permit me to disagree :)

      I think the issue is with the JS specification and not its dynamic nature. Python will throw an error for this same issue because it doesn’t assign a default value to variables.

      Aside, Java allows you to declare member variables at the bottom of classes too.

      Like

  3. It is just that in static environment the totality of errors is reduced by compile time checking. Some level of sanity is
    maintained before the code even leaves your IDE. This is a classic argument (http://stackoverflow.com/questions/125367/dynamic-type-languages-versus-static-type-languages)
    I only strongly believe that static is better in large code base and perhaps an hybrid-ish language (scala, c# also) may even be
    the way to go to accomodate both paradigm.

    Your Java analogy isn’t clear. There is nothing like “bottom” of class. Its either in the scope of the class aka member variable
    or in the scope of a method aka local variable etc.

    Like

    1. I agree that for large codebases, dynamic languages make it difficult – the major reason being the fact
      that you can’t be too sure you didn’t break something while making changes.

      Sorry if I wasn’t clear, but it’s exactly the same issue. Member variables are available in the scope of a class regardless of where they appear in the actual code (top, bottom, middle) – it’s up to the parser) to sort out placement.

      Regarding JS too, it’s the same, the variables are immediately available in the enclosing scope however they can’t be used until they are initialized.

      Like

  4. This may be a stupid question, but if due to hoisting, function declarations are immediately available in scope and function expressions are not, in what scenario would it be advantageous to use a function expression?

    Like

    1. No it is not stupid in any way :)

      Function expressions are extremely useful – they are what make functional programming principles (e.g. currying, partial applications etc) applicable.

      Moreover they are used in achieving OOP (you assign function expressions to properties) and IIFEs (https://abdulapopoola.com/2014/04/16/the-immediately-invoked-function-expression/).

      Hope this helps – please let me know if you need more information.

      Like

      1. No, that makes sense when you put it that way. I’m just trying to take my javascript to the next level and I guess I’m having a rough time understanding the “WHEN” and “WHY”. For exampleyou mentioned OOP, I still have no idea why I’d use this.someFunction = blah VS Obj.prototype.someFunction = blah. I kinda know what currying is… not sure why I’d ever use it. Maybe thats just for more advanced scripts. I did read the IIFE article. good stuff. I still don’t like that you can accidentally overwrite a variable outside of the IIFE, but thats another issue.

        var important = ‘The meaning of life!’;

        (function(){
        important = ‘Cat pictures’; // Oops!, forgot var
        })();

        alert(important);

        Anyway, I look forward to reading more of your blog.

        Like

      2. Thanks Dr Brown Sugar for the compliment :)

        this.someFunction adds ‘someFunction’ on to the ‘this’ object while Obj.prototype.someFunction will ensure that the function is available on all object instances. Both are useful depending on the context.

        Currying is good and helps to keep code terse and reduce duplication.

        JavaScript scoping is weird; I would say it’s a double-edged sword and can help as well as be dangerous.

        Thanks for your feedback and comments! I really appreciate them all.

        Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.