Andrew M
Andrew M

Reputation: 4288

Object has no Method on Async Script

I have my own custom Javascript object, defined as follows:

function NewObject(){
   this.fetchConfig();
}

NewObject.prototype.fetchConfig = function(params){
    [Code]
}

I've omitted the actual implementation for brevity, but I do nothing special other than the above. The issue is, when I actually embed the script similar to the way Google Analytics is embedded (see below), I get Uncaught TypeError: Object #<NewObject> has no method 'fetchConfig'.

I never saw this issue before I used the Async code below, which is essentially Google's modified to point to my script instead of Google Analytics.

The embed code I use:

<script>_object_id = 19782135;
    var tb = document.createElement('script'); tb.type = 'text/javascript';
    tb.async = true; tb.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cfurl.cloudfront.net/script.min.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(tb, s);
</script>

Could this issue be caused by using the async property (e.g. the script is executed before the prototype has been modified)? I tried using the web debugger and inspecting the prototype of the NewObject, but I only see the constructor-- none of the other methods I wrote appear in the debugger at all...

Upvotes: 0

Views: 320

Answers (1)

Joseph
Joseph

Reputation: 119867

Now I see your error clearly with your complete code.

In JavaScript, how you write your code is not the way how the parser actually reads it. It is read according to a certain order which is summarized in 3 groups:

  1. variable declarations
  2. function declarations
  3. All others, according to the order they appear in the scope. This includes

    • operations (function calls, conditionals, loops etc.)
    • variable assignments (variables, function expressions, prototype assignments)
    • everything else I missed

For example, this code:

new foo();
function foo(){...}
foo.prototype.bar = function(){...};
var bar = 'baz';

actually looks like this to the parser:

var bar;                          //variable declaration
function foo(){...};              //function declaration
                                  //operations and assignments
new foo();                        //this is foo, but no bar yet
foo.prototype.bar = function(){}; //function expressions (prototype assignment)
bar = 'baz';                      //variable assignment

You can test the following code to see how the variable is undefined instead of at console.log() even when in the code, the declaration comes after it. It's because the declaration is "hoisted up" but not the assignment. So it sees the variable, but not the value. A comparison is made with a non-existent variable to see the difference:

console.log('ndefined is:',ndefined);     //undefined, sees the variable
console.log('notDefined is:',notDefined); //not defined, non-existent variable
var ndefined = 'I should be defined!!!';

Now in your code, this code:

if (_object_id) {...new NewObject(_object_id)...}

function NewObject(params) {...return this.fetchConfig(params)...}

NewObject.prototype.fetchConfig = function (id) {}

appears like this to the parser due to the order which it parses:

//priority 2: function declarations
//function declarations are "hoisted up"
function NewObject(params) {...return this.fetchConfig(params)...}

//priority 3: assignments and operations
//at this point, fetchConfig is not yet in the prototype
//yet your constructor uses it, hence the error
if (_object_id) {...new NewObject(_object_id)...}

NewObject.prototype.fetchConfig = function (id) {}

In short, the if statement saw your constructor because it was hoisted up. But the constructor never had fetchConfig by that time. To fix this, change the order:

function NewObject(params) {...return this.fetchConfig(params)...}

if (_object_id) {...new NewObject(_object_id)...}

NewObject.prototype.fetchConfig = function (id) {}

The best practice would be to declare stuff or operate on them the way the parser does it. This also means formatting your code in that manner. This way, it will clear up some confusion regarding the code.

Upvotes: 1

Related Questions