Test whether variable declared yet in containing scope











up vote
1
down vote

favorite












I have an inner function that references a variable initialized by its containing outer function:



function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};


However, there are some circumstances where the inner function may be invoked before the statement defining foo has executed. In this case, any reference to foo causes a ReferenceError in the inner function:



function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


This is surprising to me, given that foo has block scope, and I am within the enclosing block when executing the inner function.



More surprisingly is that even attempting to detect this situation with the typeof operator - which I always understood to be a safe way to test for undefined variables - causes the same ReferenceError:



function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


Edit: I now understand that this behavior is the result of the "temporal dead zone" involving let and const variables discussed elsewhere. However, I'm still looking for a clean, safe way to handle the situation.



Is there any safe way to test whether a block-scoped variable (e.g., one created with 'let' or 'const') has yet reached its declaration?










share|improve this question
























  • Use this keyword => this.foo to make sure the variable declared or not.
    – Nattamai Jawaharlal Manikandan
    Nov 11 at 20:51












  • @NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
    – Myk Willis
    Nov 11 at 21:50










  • "Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
    – Bergi
    Nov 11 at 22:29










  • @Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
    – Myk Willis
    Nov 13 at 6:40










  • @MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
    – Bergi
    Nov 13 at 8:39















up vote
1
down vote

favorite












I have an inner function that references a variable initialized by its containing outer function:



function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};


However, there are some circumstances where the inner function may be invoked before the statement defining foo has executed. In this case, any reference to foo causes a ReferenceError in the inner function:



function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


This is surprising to me, given that foo has block scope, and I am within the enclosing block when executing the inner function.



More surprisingly is that even attempting to detect this situation with the typeof operator - which I always understood to be a safe way to test for undefined variables - causes the same ReferenceError:



function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


Edit: I now understand that this behavior is the result of the "temporal dead zone" involving let and const variables discussed elsewhere. However, I'm still looking for a clean, safe way to handle the situation.



Is there any safe way to test whether a block-scoped variable (e.g., one created with 'let' or 'const') has yet reached its declaration?










share|improve this question
























  • Use this keyword => this.foo to make sure the variable declared or not.
    – Nattamai Jawaharlal Manikandan
    Nov 11 at 20:51












  • @NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
    – Myk Willis
    Nov 11 at 21:50










  • "Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
    – Bergi
    Nov 11 at 22:29










  • @Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
    – Myk Willis
    Nov 13 at 6:40










  • @MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
    – Bergi
    Nov 13 at 8:39













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have an inner function that references a variable initialized by its containing outer function:



function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};


However, there are some circumstances where the inner function may be invoked before the statement defining foo has executed. In this case, any reference to foo causes a ReferenceError in the inner function:



function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


This is surprising to me, given that foo has block scope, and I am within the enclosing block when executing the inner function.



More surprisingly is that even attempting to detect this situation with the typeof operator - which I always understood to be a safe way to test for undefined variables - causes the same ReferenceError:



function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


Edit: I now understand that this behavior is the result of the "temporal dead zone" involving let and const variables discussed elsewhere. However, I'm still looking for a clean, safe way to handle the situation.



Is there any safe way to test whether a block-scoped variable (e.g., one created with 'let' or 'const') has yet reached its declaration?










share|improve this question















I have an inner function that references a variable initialized by its containing outer function:



function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};


However, there are some circumstances where the inner function may be invoked before the statement defining foo has executed. In this case, any reference to foo causes a ReferenceError in the inner function:



function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


This is surprising to me, given that foo has block scope, and I am within the enclosing block when executing the inner function.



More surprisingly is that even attempting to detect this situation with the typeof operator - which I always understood to be a safe way to test for undefined variables - causes the same ReferenceError:



function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};


Edit: I now understand that this behavior is the result of the "temporal dead zone" involving let and const variables discussed elsewhere. However, I'm still looking for a clean, safe way to handle the situation.



Is there any safe way to test whether a block-scoped variable (e.g., one created with 'let' or 'const') has yet reached its declaration?







javascript typeof






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 11 at 21:08

























asked Nov 11 at 20:48









Myk Willis

5,83011936




5,83011936












  • Use this keyword => this.foo to make sure the variable declared or not.
    – Nattamai Jawaharlal Manikandan
    Nov 11 at 20:51












  • @NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
    – Myk Willis
    Nov 11 at 21:50










  • "Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
    – Bergi
    Nov 11 at 22:29










  • @Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
    – Myk Willis
    Nov 13 at 6:40










  • @MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
    – Bergi
    Nov 13 at 8:39


















  • Use this keyword => this.foo to make sure the variable declared or not.
    – Nattamai Jawaharlal Manikandan
    Nov 11 at 20:51












  • @NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
    – Myk Willis
    Nov 11 at 21:50










  • "Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
    – Bergi
    Nov 11 at 22:29










  • @Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
    – Myk Willis
    Nov 13 at 6:40










  • @MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
    – Bergi
    Nov 13 at 8:39
















Use this keyword => this.foo to make sure the variable declared or not.
– Nattamai Jawaharlal Manikandan
Nov 11 at 20:51






Use this keyword => this.foo to make sure the variable declared or not.
– Nattamai Jawaharlal Manikandan
Nov 11 at 20:51














@NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
– Myk Willis
Nov 11 at 21:50




@NattamaiJawaharlalManikandan The property this.foo would be something completely distinct from the variable defined in this scope.
– Myk Willis
Nov 11 at 21:50












"Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
– Bergi
Nov 11 at 22:29




"Is there any safe way to test whether a block-scoped variable has yet reached its initialisation?" - no, not really, except for try/catch. But what would you need this for? Either you will want to use the variable or you don't. If it throws an error because you try to access it before it is initialised, don't work around it but just fix your mistake - calling inner() in the last line.
– Bergi
Nov 11 at 22:29












@Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
– Myk Willis
Nov 13 at 6:40




@Bergi The reason this is needed in "real" code is because inner() is an error handling function, and outer() is a request processing function. In inner() (the error handling function), I want to gather all of the context information collected by outer() so that I can write it to an error response. foo, in the real world, is a variable that is the result of parsing input values to outer(), but there are conditions where we encounter an error before foo is initialized. Thus, inner() may have to be called before foo is initialized.
– Myk Willis
Nov 13 at 6:40












@MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
– Bergi
Nov 13 at 8:39




@MykWillis Can you make an example of how you are detecting the error? Is it a try-catch? I'm unclear what the exact scope of inner and foo would be, wouldn't they be nested in different blocks? Also for what you described, I would recommend to simply use var (or put the let declarations at the top of your scope).
– Bergi
Nov 13 at 8:39












2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:



function outer() {
function inner() {
let fooExists = false;
try { fooExists = typeof foo !== 'undefined' } catch(e) {}
if (fooExists) { /* ... */ }
}

inner(); // no error
let foo = 'bar';
}


It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:



function outer() {
// due to hoisting, there is a logical `var foo;` here
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}

inner(); // no error; `foo` has been hoisted
var foo = 'bar';
}


A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:



function outer() {
let foo;
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}

inner(); // no error
foo = 'bar';
}


This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.






share|improve this answer






























    up vote
    -1
    down vote














    function outer() {
    function inner() {
    if (foo) { ... } // ReferenceError: foo is not defined
    }
    inner();
    let foo = 'bar';
    };


    This is surprising to me, given that foo has block scope, and I am
    within the enclosing block when executing the inner function.




    Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:



    function outer() {
    let foo; // declaration only, so still undefined value
    function inner() {
    if (foo) { ... } // ReferenceError: foo is not defined
    }
    inner();
    foo = 'bar'; // Not initialized until after you call inner!
    };


    Simply move the initialization up in the block and it will work:



    function outer() {
    let foo = 'bar'; // declared and initialized
    function inner() {
    if (foo) { ... } // works as expected
    }
    inner();
    };





    share|improve this answer

















    • 2




      The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
      – Myk Willis
      Nov 11 at 21:42










    • And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
      – Myk Willis
      Nov 11 at 21:43






    • 2




      "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
      – Spencer Wieczorek
      Nov 11 at 21:43










    • @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
      – Scott Marcus
      Nov 11 at 22:17










    • @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
      – Scott Marcus
      Nov 11 at 22:18











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53253082%2ftest-whether-variable-declared-yet-in-containing-scope%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:



    function outer() {
    function inner() {
    let fooExists = false;
    try { fooExists = typeof foo !== 'undefined' } catch(e) {}
    if (fooExists) { /* ... */ }
    }

    inner(); // no error
    let foo = 'bar';
    }


    It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:



    function outer() {
    // due to hoisting, there is a logical `var foo;` here
    function inner() {
    if (typeof foo !== 'undefined') { /* ... */ }
    }

    inner(); // no error; `foo` has been hoisted
    var foo = 'bar';
    }


    A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:



    function outer() {
    let foo;
    function inner() {
    if (typeof foo !== 'undefined') { /* ... */ }
    }

    inner(); // no error
    foo = 'bar';
    }


    This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.






    share|improve this answer



























      up vote
      2
      down vote



      accepted










      One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:



      function outer() {
      function inner() {
      let fooExists = false;
      try { fooExists = typeof foo !== 'undefined' } catch(e) {}
      if (fooExists) { /* ... */ }
      }

      inner(); // no error
      let foo = 'bar';
      }


      It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:



      function outer() {
      // due to hoisting, there is a logical `var foo;` here
      function inner() {
      if (typeof foo !== 'undefined') { /* ... */ }
      }

      inner(); // no error; `foo` has been hoisted
      var foo = 'bar';
      }


      A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:



      function outer() {
      let foo;
      function inner() {
      if (typeof foo !== 'undefined') { /* ... */ }
      }

      inner(); // no error
      foo = 'bar';
      }


      This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.






      share|improve this answer

























        up vote
        2
        down vote



        accepted







        up vote
        2
        down vote



        accepted






        One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:



        function outer() {
        function inner() {
        let fooExists = false;
        try { fooExists = typeof foo !== 'undefined' } catch(e) {}
        if (fooExists) { /* ... */ }
        }

        inner(); // no error
        let foo = 'bar';
        }


        It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:



        function outer() {
        // due to hoisting, there is a logical `var foo;` here
        function inner() {
        if (typeof foo !== 'undefined') { /* ... */ }
        }

        inner(); // no error; `foo` has been hoisted
        var foo = 'bar';
        }


        A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:



        function outer() {
        let foo;
        function inner() {
        if (typeof foo !== 'undefined') { /* ... */ }
        }

        inner(); // no error
        foo = 'bar';
        }


        This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.






        share|improve this answer














        One brute-force approach is to simply catch the exception thrown by typeof in the "temporal dead zone" before foo has been initialized:



        function outer() {
        function inner() {
        let fooExists = false;
        try { fooExists = typeof foo !== 'undefined' } catch(e) {}
        if (fooExists) { /* ... */ }
        }

        inner(); // no error
        let foo = 'bar';
        }


        It is also possible to use var instead of let to work around this issue. Because var is function-scoped, the declaration will be hoisted to the top of outer, making the variable available (though undefined) at all times outer is executing:



        function outer() {
        // due to hoisting, there is a logical `var foo;` here
        function inner() {
        if (typeof foo !== 'undefined') { /* ... */ }
        }

        inner(); // no error; `foo` has been hoisted
        var foo = 'bar';
        }


        A similar approach could be taken by putting the declaration (but not initialization) of foo at the top of the outer function while still using let:



        function outer() {
        let foo;
        function inner() {
        if (typeof foo !== 'undefined') { /* ... */ }
        }

        inner(); // no error
        foo = 'bar';
        }


        This last solution would seem to be the cleanest solution for the example given in the question. Unfortunately, it cannot be used when using const variables.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 11 at 21:27

























        answered Nov 11 at 21:04









        Myk Willis

        5,83011936




        5,83011936
























            up vote
            -1
            down vote














            function outer() {
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            let foo = 'bar';
            };


            This is surprising to me, given that foo has block scope, and I am
            within the enclosing block when executing the inner function.




            Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:



            function outer() {
            let foo; // declaration only, so still undefined value
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            foo = 'bar'; // Not initialized until after you call inner!
            };


            Simply move the initialization up in the block and it will work:



            function outer() {
            let foo = 'bar'; // declared and initialized
            function inner() {
            if (foo) { ... } // works as expected
            }
            inner();
            };





            share|improve this answer

















            • 2




              The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
              – Myk Willis
              Nov 11 at 21:42










            • And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
              – Myk Willis
              Nov 11 at 21:43






            • 2




              "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
              – Spencer Wieczorek
              Nov 11 at 21:43










            • @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
              – Scott Marcus
              Nov 11 at 22:17










            • @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
              – Scott Marcus
              Nov 11 at 22:18















            up vote
            -1
            down vote














            function outer() {
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            let foo = 'bar';
            };


            This is surprising to me, given that foo has block scope, and I am
            within the enclosing block when executing the inner function.




            Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:



            function outer() {
            let foo; // declaration only, so still undefined value
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            foo = 'bar'; // Not initialized until after you call inner!
            };


            Simply move the initialization up in the block and it will work:



            function outer() {
            let foo = 'bar'; // declared and initialized
            function inner() {
            if (foo) { ... } // works as expected
            }
            inner();
            };





            share|improve this answer

















            • 2




              The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
              – Myk Willis
              Nov 11 at 21:42










            • And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
              – Myk Willis
              Nov 11 at 21:43






            • 2




              "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
              – Spencer Wieczorek
              Nov 11 at 21:43










            • @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
              – Scott Marcus
              Nov 11 at 22:17










            • @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
              – Scott Marcus
              Nov 11 at 22:18













            up vote
            -1
            down vote










            up vote
            -1
            down vote










            function outer() {
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            let foo = 'bar';
            };


            This is surprising to me, given that foo has block scope, and I am
            within the enclosing block when executing the inner function.




            Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:



            function outer() {
            let foo; // declaration only, so still undefined value
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            foo = 'bar'; // Not initialized until after you call inner!
            };


            Simply move the initialization up in the block and it will work:



            function outer() {
            let foo = 'bar'; // declared and initialized
            function inner() {
            if (foo) { ... } // works as expected
            }
            inner();
            };





            share|improve this answer













            function outer() {
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            let foo = 'bar';
            };


            This is surprising to me, given that foo has block scope, and I am
            within the enclosing block when executing the inner function.




            Because of hoisting, the declaration for foo is hoisted to the top of the block, but not the initialization of the variable. It executes as if you had written:



            function outer() {
            let foo; // declaration only, so still undefined value
            function inner() {
            if (foo) { ... } // ReferenceError: foo is not defined
            }
            inner();
            foo = 'bar'; // Not initialized until after you call inner!
            };


            Simply move the initialization up in the block and it will work:



            function outer() {
            let foo = 'bar'; // declared and initialized
            function inner() {
            if (foo) { ... } // works as expected
            }
            inner();
            };






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 11 at 21:32









            Scott Marcus

            38.3k51936




            38.3k51936








            • 2




              The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
              – Myk Willis
              Nov 11 at 21:42










            • And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
              – Myk Willis
              Nov 11 at 21:43






            • 2




              "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
              – Spencer Wieczorek
              Nov 11 at 21:43










            • @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
              – Scott Marcus
              Nov 11 at 22:17










            • @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
              – Scott Marcus
              Nov 11 at 22:18














            • 2




              The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
              – Myk Willis
              Nov 11 at 21:42










            • And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
              – Myk Willis
              Nov 11 at 21:43






            • 2




              "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
              – Spencer Wieczorek
              Nov 11 at 21:43










            • @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
              – Scott Marcus
              Nov 11 at 22:17










            • @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
              – Scott Marcus
              Nov 11 at 22:18








            2




            2




            The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
            – Myk Willis
            Nov 11 at 21:42




            The declaration of foo is apparently not logically moved to the top of the outer() function (because if it was, typeof foo would return 'undefined' without an exception). This would be the behavior if I had used var to define foo, but in the case of let (and const) it is apparently not so. e.g., stackoverflow.com/a/31222689/925478
            – Myk Willis
            Nov 11 at 21:42












            And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
            – Myk Willis
            Nov 11 at 21:43




            And as for moving the initialization to the top of outer(), that is unfortunately not possible in the actual production code I have, which initializes foo based on a function call that is only performed after a bunch of preprocessing work. e.g., we don't know the value to which it should be initialized until far down in the function.
            – Myk Willis
            Nov 11 at 21:43




            2




            2




            "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
            – Spencer Wieczorek
            Nov 11 at 21:43




            "It executes as if you had written" - This is incorrect. One will give an error, the other will not.
            – Spencer Wieczorek
            Nov 11 at 21:43












            @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
            – Scott Marcus
            Nov 11 at 22:17




            @MykWillis The declaration of foo is moved to the top of the block (hoisted) as referenced by your link as well as here. It's just that let scoped variables have a "temporal dead zone" which prevents access to them prior to initialization.
            – Scott Marcus
            Nov 11 at 22:17












            @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
            – Scott Marcus
            Nov 11 at 22:18




            @SpencerWieczorek I meant it processes logically as if it was written the way I showed. In other words, it's hoisted. The fact that it throws an error doesn't preclude hoisting.
            – Scott Marcus
            Nov 11 at 22:18


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53253082%2ftest-whether-variable-declared-yet-in-containing-scope%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Florida Star v. B. J. F.

            Danny Elfman

            Lugert, Oklahoma