ECMAScript 6 bounded block function Strange behavior

I've been reading new features in ECMA6. One of the new features is Limited Block Features . This means that we can have the same name for functions in different blocks. As in the code below block1 foo()

logs 1

, then similar to block2 foo()

logs 2 and block0 foo() or global scope

logs 4. And this is the expected result. But what I can't figure out is why the last console.log(foo())

log is 1 and not 4 because it is under block0 or global scope

, instead it logs 1 which is block1 foo()

.

//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
		//block1
    function foo () { return 1 }
    console.log(foo());//will log 1
    {
    //block2
        function foo () { return 2 }//a block level function
        console.log(foo());//will log 2
    }
    console.log(foo());//will again log 1
}
console.log(foo());//should log 4 but logs 1 why?
      

Run codeHide result


Now if I add the above code in another block, it works as expected. It confuses me a little. What is actually causing this behavior?

{//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
		//block1
    function foo () { return 1 }
    console.log(foo());//will log 1
    {
    //block2
        function foo () { return 2 }
        console.log(foo());//will log 2
    }
    console.log(foo());//will again log 1
}
console.log(foo());//will log 4 but 
}
      

Run codeHide result


+3


source to share


3 answers


Completely modified answer for an in-depth explanation

First of all: the problem occurs due to the fact that you are not using the mode use strict

. What is the difference in mode strict

and non-strict

in this case? The difference is how the simplest viewport is handled.

In both modes, the parenthesis block creates a region. Declarations within this scope can be viewed within the scope itself and inside other private scopes.

{ // level 1 scope
  function asdf() {alert("asdf");}
  { // level 2 scope
    asdf(); // Yay I can use it!
  }
}

      

However , in ES5 and ES6, a non strict

simple block area is not considered a true enclosing area. Declarations within a simple block scope are raised all the way to the first true enclosing scope they can find. In these cases, the true enclosing scope is either the scope or the global scope.

The above example in mode is non strict

equivalent to this:



var asdf0 = undefined; // Haha! The declaration has been hoisted up to the global scope!
{ // level 1 scope
  function asdf1() {alert("asdf");}
  asdf0 = asdf1; // The definition is ready and will be assigned to its declaration
  { // level 2 scope
    asdf1(); // Yay I can use it!
  }
}
asdf0(); // Damn! I have access outside of the block scope due to hoisting! Should have used strict mode...

      

If we add the previous logic in function

, we don't get hoisting into the global scope just up to the function scope.

function scopeBlocker() {
  var asdf0 = undefined;
  ...
  ...
}
asdf0(); // Exception! Wasn't hoisted all the way up to the global scope!

      

Now to come to your example, because you are not using strict mode

, you have fallen into the trap of an old survey. In your first attempt, the second ad within the first block's scope was raised all the way to its enclosing scope and replaced the first ad foo

. Now, since the lift only happens once, the following ads have not been raised, so they don't replace anything. In the second case, the addition of a top-level block scope caused the first ad to foo

be hoisted into the global enclosing scope, and therefore the second ad foo

was now not hoisted because the foo

name had already been hoisted.

This is really strange behavior, but I believe what is happening here.

+1


source


You need to make sure that strict mode is enabled. Since it is enabled in modules by default, I guess your code example does not show this. The Kangax compatibility chart shows the corresponding test.



"use strict";
//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
		//block1
    function foo () { return 1 }
    console.log(foo());//will log 1
    {
    //block2
        function foo () { return 2 }//a block level function
        console.log(foo());//will log 2
    }
    console.log(foo());//will again log 1
}
console.log(foo());//logs 4
      

Run codeHide result


+1


source


I think it depends on where you are using your code. This feature may not yet be supported. Your code snippet contains 4, 1, 2, 2, 2 (Firefox browser).

Logically your code should register as you say.

Where exactly do you check the code?

0


source







All Articles