Reputation: 4288
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
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:
All others, according to the order they appear in the scope. This includes
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