Reputation: 11
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
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.
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
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
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
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