iksose
iksose

Reputation: 229

JavaScript properties with setter methods aren't real properties?

function Name(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = first + " " + last
}

Name.prototype = {
  get fullName() {
    return this.first + " " + this.last;
  },

  set fullName(name) {
    var names = name.split(" ");
    this.first = names[0];
    this.last = names[1];
  }
};

var person = new Name("Foo", "Bar");
// person.fullName = "Foo Bar"
person.hasOwnProperty("fullName") // false

Is there a way to return the properties?

Upvotes: 8

Views: 422

Answers (3)

JLRishe
JLRishe

Reputation: 101710

As InvernoMuto points out, Object.hasOwnProperty("fullName") returns false because it is not person's own property; it is inherited via the prototype chain. When you use this.fullName = "..."; in your constructor, you are invoking the inherited setter, not adding a new property.

If you want to find such properties, you can:

  1. Use a for..in loop:
for (var prop in person) {
    // this will iterate over EVERY property in person's prototype chain
}
  1. Attach the properties in your constructor:

function Name(first, last) {
  this.first = first;
  this.last = last;

  Object.defineProperty(this, "fullName", {
    get: function() {
      return this.first + " " + this.last;
    },
    set: function(name) {
      var names = name.split(" ");
      this.first = names[0];
      this.last = names[1];
    }
  });
}

var person = new Name("Ronald", "McDonald");
console.log(person.hasOwnProperty("fullName")); // true

  1. Create a whole new object in your constructor, using the get/set syntax that you have there. In this case, we wouldn't use the new keyword but just call the function:

function Name(first, last) {
    return {
        first: first,
        last: last, 

        get fullName() { return this.first + " " + this.last; },
        set fullName(name) { 
            var names = name.split(" ");
            this.first = names[0];
            this.last = names[1];
        }
    };
};

var person = Name("Ronald", "McDonald");
console.log(person.hasOwnProperty("fullName")); // true

Upvotes: 3

invernomuto
invernomuto

Reputation: 10211

hasOwnProperty does not check down the object's prototype chain, in your case person get and set are inherited through the prototype chain

hasOwnProperty

Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object; unlike the in operator, this method does not check down the object's prototype chain.

function Name(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = first + " " + last;
}
var person = new Name("Foo", "Bar");
console.log(person.fullName);
console.log(person.hasOwnProperty("fullName")); // true
console.log(Name.prototype.hasOwnProperty("fullName")); // false

for (var prop in person) {
    console.log(prop);
}

console.log('');

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};
var person2 = new Name("Foo", "Bar");
console.log(person2.fullName);
console.log(person2.hasOwnProperty("fullName")); // false
console.log(Name.prototype.hasOwnProperty("fullName")); // true

Quote @JLRishe

When you use this.fullName = "..."; in your constructor, you are invoking the inherited setter, not adding a new property.

If you want to find such properties, you can just use a for... in statement:

for (var prop in person) {
    console.log(prop);
}

Upvotes: 6

Keenan Lidral-Porter
Keenan Lidral-Porter

Reputation: 1636

According to MDN "The get syntax binds an object property to a function that will be called when that property is looked up." This means that whenever you try to access fullName of an instance of Name (e.g. person.fullName), javascript will delegate to that getter function, which happens to lie on the Name.prototype object.

Additionally, "The set syntax binds an object property to a function to be called when there is an attempt to set that property." So even though are explicitly giving each instance a fullName property, javascript actually looks to that set function on the prototype. If you want to get around this, and have person.hasOwnProperty("fullName") return true, you could do something like this:

function Name(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = first + " " + last
}

Name.prototype.setFullName = function(fullName){
  var names = fullName.split(" ");
  this.first = names[0];
  this.last = names[1];
  this.fullName = fullName;
};

var person = new Name("Foo", "Bar");
// person.fullName = "Foo Bar"
person.hasOwnProperty("fullName") // true

Upvotes: 0

Related Questions