2

I am trying to fix some Javascript that uses functions and prototype functions. For some reason the prototype function is always undefined when I try to access it and I can't figure out why.

Here is a simple example of what I'm trying to do. Basically, I want to reference the _open prototype from within the original Container function declaration using this.

Container();

function Container() {
    alert(this._open);
}

Container.prototype._open = function() {
    alert("hey");
}

You can see in fiddle that it just alerts "undefined." But this question and this question both show examples of people doing this. Why do I keep getting undefined?

Community
  • 1
  • 1
Mike S
  • 10,830
  • 6
  • 36
  • 67

4 Answers4

8

Three things:

  • use new Container(); instead of Container();.
  • Move this new Container(); line AFTER all prototype additions.
  • Call this._open(); instead of alert(this._open); to actually execute the function.

So your code should look like this:

function Container() {
    this._open();
}   
Container.prototype._open = function() {
    alert('open');
}
new Container();

Hope this helps.

Tahir Ahmed
  • 5,389
  • 2
  • 13
  • 25
2
function Container() {
    this._open();
}

Container.prototype._open = function() {
    alert("hey");
}

var container = new Container();

Try the above. You need to create an instance of the object using new. Otherwise this refers to the global object and not the prototype members.

Using constructors without new() causes weird bugs. Since this will refer to the global objected === window.

TGH
  • 37,121
  • 10
  • 94
  • 126
  • Interestingly, your suggestion makes this worse. It doesn't fix the undefined issue. And it **also** prevents the solution in Cort3z's answer from working. – Mike S Jun 03 '15 at 23:21
  • "Otherwise this refers to the global object and not the prototype members." that is really great piece of information. But one thing I don't understand. `this._open` is still undefined here. However, if you put the `new Container();` at the end then it is defined. Any idea why? – Mike S Jun 03 '15 at 23:33
  • Just to be clear you can make the call to `this._open()` whether it is before or after, yet one way it is defined and the other it is undefined. Maybe this is worthy of a completely separate question? – Mike S Jun 03 '15 at 23:34
  • this.open refers to a different function. https://developer.mozilla.org/en-US/docs/Web/API/Window/open 'this' in that case refers to the global object - window.open(). It is not the open function method defined on your prototype. In other words _ does not have a special meaning in JS – TGH Jun 03 '15 at 23:37
  • Wow thank you, that explains why `.open` is **only** defined when I was not instantiating a new instance of `Container`... because `this` referred to the global object. So my comment originally had a typo, I meant `_open` instead of `open`. I meant to ask why the `_open` function is still undefined in your answer, despite being able to call the function. – Mike S Jun 03 '15 at 23:43
  • You also have to move the assignment statement to the prototype to be BEFORE you create the new object. The code executes from top down and here the constructor is called before the new method is added to the prototype. – jfriend00 Jun 03 '15 at 23:45
  • @jfriend00 that doesn't explain the reason that you can call the function even though it is the attribute `_open` is claimed to be undefined. Does you understand why? – Mike S Jun 03 '15 at 23:49
  • @MikeSlutsky - `this._open` is undefined for all the reasons in Tahir's answer. He has everything correct. Please read (and accept) that answer. – jfriend00 Jun 03 '15 at 23:50
  • It's not undefined now that it's been assigned to the prototype before using it. Try now – TGH Jun 03 '15 at 23:50
  • @TGH you're correct, if you instantiate the object after the prototype declaration then it is defined. But the one thing I do not understand is if you reverse the order (put the instantiation above the prototype declaration): why are you able to CALL the `_open` function even though it says it's undefined if you try to access it is an attribute. How can it be both undefined AND be a callable function at the same time? – Mike S Jun 03 '15 at 23:52
  • It fails to call it as a function because it's not yet defined as a function. It is however a valid uninitialized property with the value of undefined. – TGH Jun 03 '15 at 23:57
  • "It fails to call it as a function because it's not yet defined as a function." That is wrong, it does NOT fail to call it as a function, it successfully calls it as a function, that is why I'm so baffled. – Mike S Jun 03 '15 at 23:59
  • Look in your console. It will say: _open is not a function – TGH Jun 03 '15 at 23:59
  • That is true, but `_open()` is a function when `_open` is undefined. – Mike S Jun 04 '15 at 00:00
1

Call Container() after the definition and with the new evaluator : var instace = new Container();

Example

function Container() {
    this._open();
}

Container.prototype._open = function(e) {
    alert("hey");
}

var instance =  new Container();

And maybe you don't need two alerts.

Tiberiu C.
  • 2,943
  • 26
  • 37
1

Your code takes advantage (perhaps unintentionally) of hoisting. So it looks like the prototype is built prior to execution but in fact it was not.

This is what your code actually looks like

function Container(){
    alert(this._open);
}//functions are "hoisted"

Container();

Container.prototype._open = function() {
    alert("hey");
}

Looking at this, it is clear that when Container() is called that the assignment to the prototype has not happened yet. Not only that, but Container() is being called like a function and not like an instantiation. What happens when Container is called like a function is that the this binding does not occur. The end result is that this takes on the global reference (assuming the script is not in strict mode). The global reference at this point does not have a reference to a _open property and as a result undefined is alerted and that is all that happens.

In order to have this to actually alert the function _open as defined here would be to first assign the property ._open to the prototype of Container before instantiating. Otherwise, that property will not exist in the created object.

Next, the instantiation must be used with the new keyword. This will call the functions constructor, set up its own execution context which comes with a ThisBinding and some environments for variables.

All in all, that would look like this

//place the definition at the top for readability
//so it is obvious that it is declared first
function Container(){
    alert(this._open);
}

//Next ensure that the _open property is defined on the prototype before
//instantiating the object
Container.prototype._open = function() {
    alert("hey");
}

//Lastly, ensure that the keyword `new` is used to start the
//process of instantiation
new Container();
Travis J
  • 77,009
  • 39
  • 185
  • 250