Link to home
Start Free TrialLog in
Avatar of elepil
elepil

asked on

How to create Accessor methods (getter/setter) with my constructor

I know how to define getter/setters with in object literal mode, e.g.:

var person = {
    ...
    get firstName() {
        return firstName;
    },
    set firstName(value) {
        firstName = value;
    }
    ...
}

Open in new window


What I'd like to know is how to make a getter/setter on this following constructor. Thanks.

function Person(firstName, lastName) {
    /**
     * Private properties and methods
     */
    var _firstName = firstName == undefined ? "" : firstName; // private
    var _lastName = lastName == undefined ? "" : lastName; // private
    var initials = function(_firstName, _lastName) { // private
            return _firstName.substr(0,1) + " " + _lastName.substr(0,1);
        };
    /**
     * Public properties and methods
     */
    this.firstName = _firstName; // [How do turn firstName and lastName into getters/setters?]
    this.lastName = _lastName;
    
    this.toString = function() {
        return firstName + " " + lastName;
    };
    this.toStringInitials = function() {
        return initials(_firstName, _lastName);
    };
};

var p = new Person("John", "Doe");
var p2 = new Person("Jane", "Dopey");

Open in new window

Avatar of elepil
elepil

ASKER

Hmm.. if there was a suggested solution, I'm not seeing it. :(
function Person(firstName, lastName) {
    /**
     * Private properties and methods
     */
    var _firstName = firstName == undefined ? "" : firstName; // private
    var _lastName = lastName == undefined ? "" : lastName; // private
    var initials = function(_firstName, _lastName) { // private
            return _firstName.substr(0,1) + " " + _lastName.substr(0,1);
        };
    /**
     * Public properties and methods
     */
    this.getFirstName = function (){
        return _firstName;
    }
    this.getLastName = function (){
        return _lastName;
    }
    this.setFirstName = function (firstName){
        _firstName = firstName;
    }
    this.setLastName = function (lastName){
        _lastName = lastName;
    }
    
    this.toString = function() {
        return _firstName + " " + _lastName;
    };
    this.toStringInitials = function() {
        return initials(_firstName, _lastName);
    };
};

var p = new Person("John", "Doe");
var p2 = new Person("Jane", "Dopey");
p.getFirstName()
"John"
p.setFirstName("Sally")
p.getFirstName()
"Sally"

Open in new window

Avatar of elepil

ASKER

Kyle, thanks for responding.

I knew how to create getter and setter functions the way you did, and as much as it works, it is not "true-to-form" to JavaScript getters/setters and is not what I was looking for.

If you look at my original post at the very top, I actually gave a sample of get/set syntax in object literal mode. The 'get' and 'set' you see are actual keywords in JavaScript. What I wanted to know was how to define, using the Javascript get/set keywords, in NON-object literal mode (in this case, a function).

Thanks.
not sure what you mean by "not-true-to-form". That is the way public methods are written in javascript.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_Getters_and_Setters
Avatar of elepil

ASKER

Kyle, what I meant by "not-true-to-form" is that you used "getFirstName/setFirstName" instead of the JavaScript keywords get and set. I was trying to create a getter/setter using those keywords because they have the added advantage of being able to access the property without seeing the words get and set. For example, if you defined the following in object literal form:

var Person = {
    _firstName: "John",
    get firstName () {
       return "First Name";
    },
    set firstName(value) {
        _firstName = value;
    }
}

You would access the firstName property as:

var p = Person();
console.log(p.firstName);

But the way you did it was define functions called getFirstName and setFirstName. That means, to access them, you'd have to say:

var p = Person();
console.log(p.getFirstName);

Do you see the distinction I am making? You did it the Java way, which is the way I'd do it in Java, too. But certain languages like Actionscript and JavaScript have the get/set constructs especially designed for getter/setters that Java doesn't have.
I hear you. I just don't think those keywords are available for functions. Though I'm sure you could do some fancy shenanigans to extend your functions with ObjectProperties or some other construct. I think it will make the code unreadable without bringing any real advantage.

If you want to use p.firstName, then you might as well write this.firstName = firstName; Making first name and last name private doesn't give you much if you are going to offer public setters for them. If you are concerned about encapsulation, any processing of first and last name can still be done in the Person object without the need for your library users to know anything about it.

If you look over the the second link I posted, the syntax you would like to use is not "recommended".

I would write it like this, since for me, it's a lot easier to read and maintain, but that is just a personal preference. I hate arguing about coding. You are welcome to "request attention" to get more eyes on this.

function Person(firstName, lastName) {

    this.firstName = firstName == undefined ? "" : firstName;
    this.lastName = lastName == undefined ? "" : lastName;
    var initials = function() { // private
            return this.firstName.substr(0,1) + " " + this.lastName.substr(0,1);
        };

    this.toString = function() {
        return this.firstName + " " + this.lastName;
    };
    this.toStringInitials = function() {
        return initials();
    };
};

Open in new window

hey, I tried and tried to get the p.firstName to be an Object reference for an Object that has the
get firstName()

but I could not do it, after failing for many different tries, I believe (for me anyway) to use an OO and have both names (first, last) in a names object, Not really a solution, but a workable to have an interactive (many values in function object changed) by simply assigning a value (no function call);

function Person2(firstName1, lastName1) {
    /* Private properties and methods */
    var _firstName = firstName1 == undefined ? "" : firstName1; // private
    var _lastName = lastName1 == undefined ? "" : lastName1; // private
    var initials = function(_firstName, _lastName) { // private
            return _firstName.substr(0,1) + " " + _lastName.substr(0,1);
        };

  this.names = {count:1,  // object
  get first() {
    return _firstName;
    },
  set first(value) {
    this.count++;
    _firstName = value+this.count;
    },
  get last() {
    return _lastName;
    },
    set last(value) {
	this.count++;
    _lastName = value+this.count;
    }
};

  this.toString = function() {
        return _firstName + " " + _lastName;
    };
  this.toStringInitials = function() {
        return initials(_firstName, _lastName);
    };
};

var p = new Person2("KILohn", "DoeJoke");

p.names.first = "New Name";
p.names.last = "How IT";
document.write("Names = "+p.names.first+" - "+p.names.last);

Open in new window

Just a way, but the functions are different than the objects for containing some operations.
@Slick812,

What advantage does this offer? Why are we trying to force the get set keywords?

Why is p.names.first better than p.getFirstName ?

I'm not being a jerk, I really would like to know what the benefit is.

The comments in this Ajaxian article are also pretty mixed:
http://ajaxian.com/archives/getters-and-setters-in-javascript
ASKER CERTIFIED SOLUTION
Avatar of Kyle Hamilton
Kyle Hamilton
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of elepil

ASKER

Kyle,

The this.firstName = firstName, while it works, would not be using getters/setters. The reason why that is important to me is because my application will very possibly need to throw an event when a property value is changed so that those that are listening can react accordingly, and that's not possible if you don't set up a setter function.

Maybe you're right, that there's no way to use the get/set keywords in a function. I'm new to this, and that's why I created this post, to try to learn from those more experienced than I am like yourself. I hate using the Object.defineProperty because the sequence of code becomes bizarre where I'd have to instantiate an object first, and then apply Object.defineProperty for each of the properties. I have experimental code that tells me this has its own problems as well. I guess I just want to implement OOP and still keep things simple (as in Java, C#, etc.), and that is getting to be problematic with JavaScript.
having said that, I'm still not sure about the wisdom of doing this.

The user of your library may get unexpected results if you process their values. I would expect that when I set Field.value, that value will not be changed. This is along the lines of modifying native functionality, for example messing with Object.prototype

I still think it is a lot clearer to provide explicit getter or setter methods. no confusion.
Hi elepil, maybe we posted at the same time. did you see the John Resig example above?

correction to above post:

var v = new Field();
v.value = "whatever"
console.log(v.value);
Avatar of elepil

ASKER

You did it, Kyle! Your solution is the only one that meets all criteria of a typical OOP object as we know with languages such as Java, C#, etc. Here's a more elaborate code sample expounding on your solution:

function Person(firstName, lastName, gender){
    /**
     * Private properties and methods
     */
    var _firstName = firstName; // private property
    var _lastName = lastName; // private property
    var _initials = function() { // private method
        return _firstName.substr(0,1) + " " + _lastName.substr(0,1);
    }
    
    /**
     * Public properties and methods
     */
    this.gender = gender; // public

    // public getter/setters for firstName and lastName
    this.__defineGetter__("firstName", function(){
        return _firstName;
    });
   
    this.__defineSetter__("firstName", function(value){
        _firstName = value;
    });

    this.__defineGetter__("lastName", function() {
        return _lastName;
    });
    
    this.__defineSetter__("lastName", function(value) {
        _lastName = value;
    })
    
    // Public methods
    this.toString = function() {
        return _firstName + " " + _lastName;
    }
    
    this.toStringInitials = function() {
        return _initials();
    }
} 

var p1 = new Person("John", "Doe", "M");
var p2 = new Person("Jane", "Bimbo", "F");

console.log(p1.firstName);
console.log(p2.lastName);
console.log(p1.toString());
console.log(p2.toStringInitials());

Open in new window


As far as I can tell, your solution provides the ability to simulate the creation of an OOP data model as used with languages like Java, C#, etc.

It allows definition of private and public properties/methods, as well as providing definition of properties by way of getters/setters.

Thanks for your help!
Avatar of elepil

ASKER

Excellent, Kyle, nailed it!! Many thanks for your help!