1

I have a form and I am adding an addEventListener() to the form. I wanted to call a function from within the addEventListener() but I am getting an Uncaught TypeError at the function call.

Code 1

$(document).ready(function(){
  function uploadFile(){
      alert("comes here");
  }

  uploadForm.addEventListener('submit', function(e) {
      var uploadFile = document.getElementById('upload-file').files;
      e.preventDefault();
      uploadFile();
  });
});

But if I change the above code to

Code 2

$(document).ready(function(){
  var test = function uploadFile(){
      alert("comes here");
  }

  uploadForm.addEventListener('submit', function(e) {
      var uploadFile = document.getElementById('upload-file').files;
      e.preventDefault();
      test();
  });
});

It works. I want to know why. It maybe something associated with the scope. But from whatever I know, I think the function(uploadFile()) and the function reference(test) has the same scope.

I am a self taught programmer so I don't know what to google to understand why this happens. The closest I got is this , function naming

As an answer, I am just looking for some terms which I can google to understand why this happens.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jitin Kodian
  • 471
  • 4
  • 14
  • This sounds weird, you should be able to call `uploadFile` from the first snippet and `test()` from the second snippet. But for anyone who wants to see it in action https://jsfiddle.net/mendesjuan/e9sa1jLc/ – Ruan Mendes Feb 11 '16 at 13:05
  • how does code 2 work ?? – nAviD Feb 11 '16 at 13:10
  • @JuanMendes Sorry for the trouble of creating the jsfiddle. It was a stupid mistake from my part – Jitin Kodian Feb 11 '16 at 13:17

2 Answers2

3

You have overridden a function name uploadFile with a variable called uploadFile, it's just a name clash

$(document).ready(function(){
  function uploadFile(){ //uploadFile function declaration
      alert("comes here");
  }

  uploadForm.addEventListener('submit', function(e) {
      //function uploadFile already declared, and now you are using var here
      var uploadFile = document.getElementById('upload-file').files;
      e.preventDefault();
      uploadFile();
  });
});

A simple name changing will help

$(document).ready(function(){
  function uploadFile2(){ //NOTICE NAME
      alert("comes here");
  }

  uploadForm.addEventListener('submit', function(e) {
      var uploadFile = document.getElementById('upload-file').files;
      e.preventDefault();
      uploadFile2(); //NOTICE NAME
  });
});

In the second example, everything is OK, as you have function name test, which doesn't clash with uploadFile variable

Also checkout @JuanMendes answer, as it explains the reasons of problem and very useful for knowledgebase

Medet Tleukabiluly
  • 11,662
  • 3
  • 34
  • 69
  • Ya. How dumb of me. Thanks Medet. I just wasted 1 hour on this. – Jitin Kodian Feb 11 '16 at 13:14
  • There's still something to be explained, why doesn't the first example that also has a named function `uploadFile` override the variable? [Shameless plug for my answer](http://stackoverflow.com/a/35340439/227299) – Ruan Mendes Feb 11 '16 at 13:20
  • @JuanMendes because it was declared with var, it will cause name clash, when it has no var, it will be override, you cannot declare `var a = 1; var a = 2;` compiler will throw exception – Medet Tleukabiluly Feb 11 '16 at 13:27
  • @Medet I know that, you have to see my answer to know what I meant. I admit it, it wasn't as well put in my comment above. – Ruan Mendes Feb 11 '16 at 13:34
2

Medet is correct, var uploadFile overrides the function uploadFile() from the outer. However, I wanted to add some additional explanation as to why var test = function uploadFile() does not really clash with the local var uploadFile

The reason is that when you assign a function to a variable, you have a function expression. Typically they are anonymous, but you have created a named function expression. In that case, the name of the function is only valid within the uploadFile function itself (can be used for recursion), that is why it doesn't clash with the uploadFile defined in the inner function.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression

If you want to refer to the current function inside the function body, you need to create a named function expression. This name is then local only to the function body (scope). This also avoids using the non-standard arguments.callee property.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217