user2359905
user2359905

Reputation: 11

Putting arrays into custom objects

I am attempting to build my first custom object and it looks something like this:

function  URLObject()
{
   this.syllables = new Array();
   etc...

   this.AddtoSyllables = AddtoSyllables;
   function AddtoSyllables(AWord)
   {
       var SylCount = this.syllables.length;
       alert("This is SylCount: " + SylCount);
   }
}

var myobj = new URLObject();
myobj.AdtoSyllables("text");

The execution of the above code results in the JS engine printing out the following:

This is Sylcount: NAN

-or-

This is SylCount: undefined.

I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.

And yet I am doing something wrong here and I do not know what. Can anyone help?

Upvotes: 1

Views: 106

Answers (4)

Dan Tao
Dan Tao

Reputation: 128447

Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.

Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.

http://jsfiddle.net/J3tUb/

That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:

function createURLObject() {
   // Use closed-over locals instead of attaching properties.
   var syllables = new Array();

   function AddToSyllables(AWord) {
     // Since syllables is closed over, it is accessible here
     // (but WON'T be accessible outside this scope).
     syllables.push(AWord);
     return syllables.length;
   }

   // Expose whatever functionality you want to be "public"
   // in the returned object.
   return {
     AddToSyllables: AddToSyllables
   };
}

var myObj = createURLObject();
myObj.AddToSyllables("text");

It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.

Upvotes: 2

stackh34p
stackh34p

Reputation: 9009

The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:

function  URLObject()
{
    //...
}

URLObject.prototype.AddtoSyllables = function (AWord)
{
    var SylCount = this.syllables.length;
    alert("This is SylCount: " + SylCount);
}

To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:

this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
    var SylCount = this.syllables.length;
    alert("This is SylCount: " + SylCount);
}

adds the AddtoSyllables function as an entry to the object this points to. The code

myobj.AdtoSyllables(...)

is equivalent to

myobj["AdtoSyllables"](...) // now a retreiaval operation

or even

var fn = myobj["AdtoSyllables"];
fn (...);

Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.

The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.


From an alternative point of view:

function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};

bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;

In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.

Upvotes: 0

ndrizza
ndrizza

Reputation: 3415

Here you go:

function  URLObject()
{
   this.syllables = [];
   etc...
}

URLObject.prototype.addToSyllables = function(aWord) {
  var SylCount = this.syllables.length;
  alert("This is SylCount: " + SylCount);
}

var myobj = new URLObject();
myobj.adtoSyllables("text");

.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())

Upvotes: 2

Emanuele Pavanello
Emanuele Pavanello

Reputation: 873

you need to do this :

function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)  

etc... Like this you can add method and attributes to one object.

Upvotes: 0

Related Questions