3

Is it possible to detect duplicate functions in Javascript (which may be written by accident in some cases)? In Google Chrome,

printLah(); //this prints "Haha" for some reason, without even printing an error message in the Javascript console!
function printLah(){
    alert("Hahah!");
}


function printLah(){
    alert("Haha");
}

Here it is on JSfiddle.

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • 1
    Read up on [hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting). – josh3736 Sep 11 '12 at 03:01
  • @josh3736 That article is wrong. The results are correct but the author's understanding of what's happening is wrong. What he is illustrating in that article has nothing to do with scoping. See this: http://stackoverflow.com/questions/3887408/javascript-function-declaration-and-evaluation-order/3887590#3887590 – slebetman Sep 11 '12 at 03:14
  • @slebetman - Why do you think that [article](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) has nothing to do with scoping? The first three examples demonstrate scoping behaviour (while also being about hoisting)... – nnnnnn Sep 11 '12 at 03:45
  • @nnnnnn Because hoisting doesn't exist in javascript. Javascript interpreters does not really work that way. "Hositing" is a behavior that emerges as a side effect of having a separate compilation and evaluation phases. Javascript does not "bring declarations to the top" instead it process all declarations in the compile phase and all assignments in the eval phase. It is less confusing once you understand this - fewer rules that govern it. – slebetman Sep 11 '12 at 03:59
  • @slebetman - My previous point was that you said that article has nothing to do with _scoping_, when several of its examples are about shadowed variables - a scoping issue. Regarding your note about how JS interpreters work - OK, yes, but still "hoisting" seems to me to be a reasonable way of informally describing the behaviour in a way that is easy to understand. (Even an imprecisely worded "hoisting" explanation will imply a parse/compile phase and an eval phase. I know JS doesn't literally move the declarations to the top.) – nnnnnn Sep 11 '12 at 04:47

3 Answers3

9

The short answer is, no it's not.

This is how javascript works. A function name is just a variable that is assigned a function. For example:

function foo () {
    alert('foo!');
}

foo = 1;

foo();

The code above will generate an error because a number is not a function! There is no difference between function names and variable names. In fact, an alternative way to define functions looks exactly like how you'd define variables:

var foo = function () {
              alert('foo!');
          }

It's because of this functions-as-first-class-objects behavior that javascript cannot prevent re-assignment otherwise you cannot re-assign variables (pure functional languages on the other hand have no problems with disallowing variable re-assignments).


Work-arounds and best practice:

This is the reason people keep saying that you shouldn't define too many globals in javascript. That includes functions. Otherwise it may clash by accident with someone else's code.

There are two powerful features in javascript that can mitigate this problem: objects and closures.

Because javascript supports objects you should use object oriented programming to limit the number of globals in your program. Unlike traditional OOP, javascript works better when using objects as collections or namespaces. This is because javascript doesn't have file scope and everything is global.

This doesn't mean you shouldn't create smaller objects that encapsulate smaller problems like you do with traditional OOP. It just means that you should, if you can, contain all your objects within a single parent object. And I don't mean inheritance here, I mean in a has-a relationship. Look at popular libraries like jQuery and Raphael for examples of this. They export only one object to the global scope to avoid clashing with other people's code.

But, again, this doesn't really protect people from re-assigning your objects (because they're variables after all). For example, you can easily break jQuery by doing this at the top of your HTML file before other bits of javascript have the chance to run:

jQuery = null;

The way to protect your code from being tampered with is to use a closure. Third party code has no access to any code you run from inside your closure. As long as you avoid globals that is.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • "A function name is just a variable that is assigned a function" - That's not entirely true. Try running this: `foo(); foo = 1; function foo () {alert('foo!');}`. See [this](http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname) – Jonathan May 15 '14 at 11:19
  • Still true. All you're demonstrating is javascript's compilation and evaluation order (otherwise misnamed as "hoisting"). Try your own code: `foo(); foo = 1; foo(); function foo () {alert('foo!');}` – slebetman May 15 '14 at 14:42
4

Just to follow on from slebetman's answer, you can use the following to check for existence before declaring a variable or function.

if (typeof(functionName) == 'undefined') {
    functionName = function() { 
        // add code here
    }
}

Once again, the reason you would do this check is because you want/need to put something in the global scope, even though it is often not needed. Not using a var puts it implicitly into the global scope.

Gerard Sexton
  • 3,114
  • 27
  • 36
-1

Try this.It work for me !!!

$(document).ready(function () {
    var all_functions = [];
    var duplicate_functions = [];
    var reportRecipientsDuplicate = [];
    for (var i in window) {

        if ((typeof window[i]).toString() == "function") {
            if (window[i].name) {
                all_functions.push(window[i].name);
            }
        }
    }

    var all_functions1 = all_functions.sort();


    for (var i = 0; i < all_functions1.length - 1; i++) {
        if (all_functions1[i + 1] == all_functions1[i]) {
            duplicate_functions.push(all_functions1[i]);
        }
    }
    console.log("Duplicate functions on page");
    console.log(duplicate_functions);
});
Satish
  • 696
  • 1
  • 11
  • 22
  • this doesn't work. your $ function is defined somewhere else in your webpage. it looks to me like it is jQuery. is that what your $ usage is? – Shawn Kovac Jul 15 '20 at 20:58
  • i tested the method in this answer, and duplicate functions do NOT show up as duplicates in the window object. this answer is utterly wrong. – Shawn Kovac Jul 15 '20 at 22:13