4

I'm trying to get my head around scoping. From my understanding ES5 does not have the ability to block-scope, therefore, inner f() should be in scope of the body test.

These are the results from running the function

  • test(true); // ["local", "local"]
  • test(false) // f is not defined

However, I cannot understand why test(false) gives an error? I was expecting - [local].

  function f() { return "global"; }

    function test(x) {
        var result = [];
        if (x) {
            function f() { return "local"; } // block-local

            result.push(f());
        }
        result.push(f());
        return result;
    }
2
  • A very similar question. Commented Dec 14, 2016 at 18:08
  • 1
    Ha! If you 'use strict' mode in Chrome 54, the results are ["local", "global"], ["global"]. So it seems it fixes things by creating scope within the if. I don't think this should be allowed, hence the inconsistent results. Otherwise this is a bug in the browser, since by my understanding the function should be available throughout the entire function and not effected by the if. Commented Dec 14, 2016 at 18:11

2 Answers 2

3

This is what your code actually looks like when it is compiled:

function f() { return "global"; }

    function test(x) {
        var result = [];
        var f; 
        if (x) {
            f = function () { return "local"; } // block-local

            result.push(f());
        }
        result.push(f());
        return result;
    }

The f variable (the variable holding the function pointer) is declared at the top of the function, but it is defined within the conditional.

JavaScript also has a feature called: strict mode. This was put in after the original development of the language to enforce some best practices and some rules to keep developers from making incorrect assumptions about how they think the language works based on other languages with a similar syntax. In this instance, strict mode actually changes the scoping of the new f function.

The following code:

function f() { return "global"; }

    function test(x) {
    "use strict" // STRICT MODE TAG INSERTED HERE
        var result = [];
        if (x) {
            function f() { return "local"; } // block-local

            result.push(f());
        }
        result.push(f());
        return result;
    }

test(true);
test(false);

produces the following results result:

["local","global"] //test(true);

["global"] //test(false);

It overrides the default scoping rules and makes sure that the new declaration of f only applies to within the conditional where it was defined.

Sign up to request clarification or add additional context in comments.

1 Comment

Would be nice to mention how strict mode is different.
0

This is because when your condition is true, 'f' is a function declaration ,so it checks for the inner f function .

When x is false,as 'f' is not visible it throws an error and it cannot see the global 'f' function because f is already overridden in the local

To override that you can either explicity call the window.f() or make the f() inside the if condition an IIFE

check these snippets

function f() {
  return "global";
}

function test(x) {

  var result = [];
  if (x) {

    // block-local
    result.push((function f() {
      return "local";
    })());
  }
  result.push(f());
  return result;
}
var res = test(true);
console.log(res);
var res1 = test(false);
console.log(res1);

Hope it helps

1 Comment

Thanks all, very clear, better than the textbook. This now makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.