3

I have two files containing JavaScript and jQuery functions. They are referenced on the page in this order:

<script src="js/kiosk-functions.js"></script>
<script src="js/kiosk-main-socket-handler.js"></script>

In kiosk-functions.js I had originally done this -

$(function() {
    // some JavaScript functions
    function isJSON(str) {
        try {
            JSON.parse(str);
            return true;
        } catch (e) {
            return false;
        }
     }
     // some jQuery code follows...
});

Then, in kiosk-main.js I had this -

$(function() {
    var socket = io();
    socket.on('message', function (data) {

        if(isJSON(data)) {
            // do stuff
        }
    });
    // other JavaScript and jQuery code
});

This resulted in the following error -

Uncaught ReferenceError: isJSON is not defined

Once I moved the isJSON() function out of the document ready handler in kiosk-functions.js then all was well, but left me puzzled. I read a number of the answers here on SO trying to understand what was going on, being under the impression that the function would be hoisted and available globally. I didn't find anything that demonstrated this example.

I'm sure that I am missing something simple here. Does the document ready handler (a function) keep the isJSON() function from being hoisted? Or is it a simple scope issue?

1
  • javascript is function scoped (not speaking about let statement). isJSON is defined under the ready handler scope Commented Jan 26, 2015 at 13:52

3 Answers 3

3

Your problem is not hoisting, but the scope of the function.

Basically in kiosk-functions.js you define a callback to document.ready and inside that callback you define the function isJSON(). The function is just known within that scope.

In the second file kiosk-main.js you try to use isJSON() as if it was defined either in that callback's scope or in the global scope. Both is not the case, hence the error.

In order to solve this, you could add some global namespace myNamespace and attach your function there:

$(function() {
    // some JavaScript functions
    function isJSON(str) {
        try {
            JSON.parse(str);
            return true;
        } catch (e) {
            return false;
        }
     }

  // init namespace
  window.myNamespace = window.myNamespace || {};

  // attach function
  window.myNamespace.isJSON = isJSON;
});

Then in the other file you can reference that global namespace to call your function:

$(function() {
    var socket = io();
    socket.on('message', function (data) {

        if(myNamespace.isJSON(data)) {
            // do stuff
        }
    });
    // other JavaScript and jQuery code
});

Edit

As mentioned by @Alnitak in the comments: In the browser the global object is window. Changed code accordingly.

Sign up to request clarification or add additional context in comments.

3 Comments

The OP mentioned jQuery - chances are he wants window rather than global.
Thanks for the explanation on using the namespace, I had not had an opportunity to make use of that but it looks like I can take advantage of it on this project.
@JayBlanchard Not anymore ,-) Thanks.
2

$(function(){}) is just a shorter version of $(document).ready(function(){});

In the above function, this is document and for a function to be global, it needs to be in window context.

Hoisting isn't your problem, the scope in which the function is declared, is.

If it is used widely in the code and if it isn't part of some specific module or library you're building, then you can just declare the function in the global context or just make the function, the property of window, which makes it global.

If it is some library or module then you can attach it to it making it specific to only that library/module.

In short, use namespacing or make it global if you really use it lot many times and is a generic function.

3 Comments

So the hoisting does not occur in that case?
@JayBlanchard it occurs but hoisting function is regarding scope
Ah! That makes sense now.
2

Variables and function definitions are only hoisted within the enclosing function scope, which in your case is the anonymous function that you've passed to $(). In that respect, hoisting is making no difference - it's simply that the isJSON function is defined in a different scope.

You may wish to consider the module namespace pattern:

var NAMESPACE = NAMESPACE || {};

NAMESPACE.isJSON = function() {
    ...
};

where NAMESPACE is a single global variable that will contain all of your locally defined functions.

The NAMESPACE || {} is there to ensure that the NAMESPACE object isn't overwritten if it already exists.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.