javascript, let function if not defined

Viewed 805

Every time a modal is opened I load via ajax some html + js, like this:

var loadModalJs = function() {
   ...
}

$(function() { loadModalJs(); });

It works with var, but if I replace var with let, when the modal is closed and then opened again I get Identifier 'loadTabJs' has already been declared

I tried something like this, without success:

if(typeof loadModalJs === 'undefined') {
    let loadModalJs = function() {
       ...
    };  
}
loadModalJs(); // ReferenceError: loadModalJs is not defined

I don't like using var because my IDE complains about "'var' used instead of 'let' or 'const'"... But none of them seems to work... How could I do?

4 Answers

The error you placed into the comment is correct: at no point do you define the variable in scope -- you define it within the the if clause, and it is not available outside of that clause, your reference to it in the if statement is to an undefined global variable.

Also, if your variable is only ever going to be undefined or a function, then no need to test its type, as undefined evaluates to false.

let loadModalJs;

// ...your other code here...


// This bit within the function/scope run multiple times:
if (!loadModalJs) {
    loadModalJs = function() {
       ...
    };  
}

if (loadModalJs) { 
  loadModalJs(); 
}

In addition to the current answer:

Your second snippet could work if you use var instead of let.

As if creates its own block {}:

  • let is limited to the immediate block {}.
  • var is limited to the immediate function block {} (or global if there are no functions).

E.g.:

if (true) {
  var x = "It'll work outside the if.";
}

console.log(x);


Edit:

As an additional tip, you might be careful with the way you 'create' functions in javascript:

  • Functions defined, e.g. let myFunction = function() { }, are under top-to-bottom flow of control (i.e. first define, then use).
  • Functions declared, e.g. function myFunction() { }, are hoisted (i.e. declare and use where you want, in the same scope).

In addition to Lee Goddard's answer. You may consider learning about the difference between let and var. The most key difference is:

let allows you to declare variables that are limited to the scope of a block statement or expression on which it is used, unlike the var keyword, which declares a variable globally, or locally to an entire function regardless of block scope. - MDN Docs

This looks like a good opportunity to use guard/default clauses:

let f = function(){
  console.log('f is defined');
}

let g;
g = f || function() {
    console.log('f was NOT defined');
}
g();
f = null;
g = f || function() {
  console.log('f was NOT defined');
}
g();

with a twist:

let f, g;



for (let i=0; i<8; i++){
  g = f || function() {
    console.log('f was NOT defined');
  }
  g();
  f = (f)?undefined:function(){console.log('f is defined');};
}

So in your case this would be:

let guardedModal = loadModalJs || function() {
        // your code here
}
guardedModal();
Related