Don P
Don P

Reputation: 63547

JS object using `this` gives an undefined result

Ok here is a very simple JS object. Three attributes are strings, the fourth is a function.

var myStringBuilder = {
  protocol: "http://",
  host: "www.mysite.com",
  fullPath: this.protocol + this.host + "/just/for/fun/",
  getFullString: function() {
    return this.fullPath;
  }
}

console.log(myStringBuilder.getFullString());  // Returns "NaN/just/for/fun"

In fullPath, this.protocol and this.host are both undefined. Why does this happen?

jsfiddle

Upvotes: 2

Views: 47

Answers (3)

luciole75w
luciole75w

Reputation: 1117

If i agree with all the valuable information in previous answers, to answer to the precise point in the question, the fullPath property is not properly defined because it is not initialized in a function context, so this does not refer to the object myStringBuilder.

Upvotes: 2

thefourtheye
thefourtheye

Reputation: 239443

Internally JavaScript objects are constructed based on a hashing algorithm. So, they keys may not logically appear in the order we define them. In this case, fullPath gets defined first and when the value is assigned, it depends on partOne and partTwo where they havn't got defined yet. That is why they are undefined while defining fullPath.

If you must construct an Object like this, I would recommend a constructor function, like this

function MyStringBuilder() {
    this.protocol = "http://";
    this.host = "www.mysite.com";
    this.fullPath = this.protocol + this.host + "/just/for/fun/";
}

MyStringBuilder.prototype.getFullString = function() {
    return this.fullPath;
}

myStringBuilder();

The advantage of this method is that, you can customize the object creation dynamically. For example, you can pass protocol or host values like this

function MyStringBuilder(protocol, host) {
    this.protocol = protocol || "http://";
    this.host     = host     || "www.mysite.com";
    this.fullPath = this.protocol + this.host + "/just/for/fun/";
}

with this change, you should be able to decide the protocol and host at runtime.

Upvotes: 2

Paul
Paul

Reputation: 27413

To get around part of the hash being undefined, you can use functions instead of calculated values. This will delay evaluation.

var myStringBuilder = {
  partOne: "http://",
  partTwo: "www.mysite.com",
  fullPath: function(){ return this.partOne + this.partTwo + "/just/for/fun/" }
}

Upvotes: 2

Related Questions