5

I'm pretty new to writing OO JS, but this has stumped me. So I setup me new Call object, then define what I assume to be empty arrays. When I call AddFieldQueryToArray() I get

Uncaught TypeError: Cannot call method 'push' of undefined 

On this.fieldArray.push(field)

I don't really know why. I've tried this.fieldArray = fieldArray; in the constructor too.

    function Call() 
    {    
         var fieldArray = new Array();
         var queryArray = new Array();
    }

    Call.prototype.AddFieldQuerysToArray = function(field,query)
    {
        if(field !== 'undefined')
        {               
            this.fieldArray.push(field);
        }

        this.queryArray.push(query);

    }
Kikimac
  • 179
  • 1
  • 3
  • 10
  • Just one comment, in JavaScript pls always put opening braces on the same line of the statement: i.e. `function call() {`, `if (field !== 'undefined') {`. This has side effects in some cases such as with `return` and a proper JS code should keep this form. – Arman Jun 10 '13 at 10:05

3 Answers3

10

You should reference instance properties with this. inside the constructor:

function Call() 
{    
     this.fieldArray = [];
     this.queryArray = [];
}

new Array() has a shortcut [] which I have used above.

If you use var fieldArray = []; you would create a local variable which is destroyed once your instance has been created unless you use this kind of construct:

function Call()
{
    var fieldArray = [];

    this.AddFieldQuerysToArray = function(field, query) {
        // ...
        fieldArray.push(field);
    }
}

This creates a closure for each instance in which fieldArray is "kept alive" throughout the instance's lifetime.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • "destroyed once your instance has been created" -- unless it's referenced from a closure – John Dvorak Jun 10 '13 at 09:17
  • @JanDvorak The given code didn't give that suggestion, but I've added an example of such a condition. – Ja͢ck Jun 10 '13 at 09:22
  • I always find adding methods to `this` inside a constructor looks ugly, with the exception of something like `function Constr() {var env = {}; this.getEnv = function (x) {if (x) return env[x];return env;};}` – Paul S. Jun 10 '13 at 09:26
  • I still get the same 'cannot call method push of undefined' . I made a fiddle: http://jsfiddle.net/nQxqG/ – Kikimac Jun 10 '13 at 09:32
  • 1
    @Jack if it's on the client side, it's visible. Also `a local variable which is destroyed once your instance has been created`, if only - `function Constr() { var secret = 'I am IRON MAN'; this.find = function (x) { return eval(x); }; } c = new Constr(); c.find('secret'); // "I am IRON MAN"` – Paul S. Jun 10 '13 at 09:36
  • @PaulS. That's no different from my answer, except that it's a more contrived example :) – Ja͢ck Jun 10 '13 at 09:39
  • @Kikimac Calling functions on the prototype directly only works if they don't use `this` to mean an instance of `Call`; you use either bind them to an instance using `.call()` or call the function on an instance instead; [fiddle](http://jsfiddle.net/nQxqG/2/). – Ja͢ck Jun 10 '13 at 09:41
  • @PaulS. Also, with information hiding I mean that you can't directly access the information without going through the "accessor" methods. Of course, anyone can read the source code, that wasn't the point :) – Ja͢ck Jun 10 '13 at 09:43
1
function Call() 
{
    this.fieldArray = [];
    this.queryArray = [];       
}


Call.prototype.AddFieldQuerysToArray = function(field,query)
{
    if(field !== 'undefined')
    {
        alert('field==='+this.fieldArray);
        this.fieldArray.push(field);
    }
    alert('field==='+this.fieldArray);  
    this.queryArray.push(query);
alert(this.queryArray);// to check
alert(this.fieldArray);// to check
};

field = 'exampleField';
query = 'exampleField';

var cally = new Call();
cally.AddFieldQuerysToArray(field,query); //change

The only problem is that you were calling Call.prototype.AddFieldQuerysToArray() method and here this value actually referred to execution context of Call.prototype object which didn't have the arrays fieldArray and queryArray.

Calling the prototype method AddFieldQuerysToArray() by coding cally.AddFieldQuerysToArray(field,query); refers to the execution context of the cally instance which has got both the arrays declared in it through its constructor.

womp
  • 115,835
  • 26
  • 236
  • 269
chetan mehta
  • 369
  • 1
  • 3
  • 13
  • alert(Object.getOwnPropertyNames(Call.prototype)); This simple code will help you understand that fieldArray and queryArray arrays aren't actually present in execution context of Call.prototype – chetan mehta Jun 10 '13 at 09:55
0

It's a very older post & the answer was given by Jack. this has to be used to avoid the Error.

But there's an anti-pattern used in the code block. new Array() should be avoided. Better approach is to use Array Literal Notation. Follow this StackOverflow answer What’s the difference between "Array()" and "[]" while declaring a JavaScript array? for details.

But the gist is that if only one parameter is given to the Array constructor then that will interpreted as length of the Array but that will NOT BE THE FIRST element in the array.

console.log(new Array(10).length);//10
console.log(new Array(10)[0] === undefined);//true
Pollob
  • 29
  • 1
  • 4