javascript property accessors

In Javascript, it seems like using property accessors is not all that common (unlike in other OO languages such as Java for example).

If I have a Person object with a name, defined as

function Person(name) {
   this.name = name;
}

A person's name is not going to change, but I do want to be able to access it when needed, so I could do something like:

function Person(name) {
   var name = name;
   this.getName = function() {
      return name;
   }
}

Even in a dynamic language, I think the principles of using getters and setters apply the same way they do to statically typed OO languages (e.g. encapsulation, adding validation, restricting access, etc)

This question may get closed as subjective, but I'm curious as to why this behavior doesn't appear more often (e.g. Java developers would go crazy if everything was public).

Is there a "standard" way to do this in javascript? I've seen Object.defineProperty, but not all browsers support that.

Answers:

Answer

Javascript has intercept-able property accessors:

http://ejohn.org/blog/javascript-getters-and-setters/

IMHO this is a far better solution to enforce the Uniform Access Principle than Java's more strict explicit getters, but that is also part of the simplicity and inflexibility of that language (Groovy for instance allows for similar interception).

Answer

I know my thoughts on the subject.

Getters and setters are evil.

Wait! Really! Bear with me a moment and let me explain.

Just using a method to get and set a value is .. well .. kinda pointless. It doesn't protect, not really, and what you put in is what you get out.

On the other hand, I'm rather fond of methods that put information in, then get information back out. BUT here is the magic part! It isn't the same information. Not directly.

function Person(name) {
  this.getFullName = function() {return this.firstName + " " + this.lastName;};
  this.setBirthday = function(date) { this.birthday = date; };

  this.getAge = function() { /* Return age based on the birthday */ };
  this.isOfLegalDrinkingAge function() { /* do your math here too */ };
}

But most of the time I'm just shoving static data in and getting static data out. What is the point of hiding it behind getters and setters?

As a secondary reason, dealing with the DOM and most host objects, you set properties. You don't play with getters and setters. Not using them fits the rest of the 'flavor' of what JS coders do.

Answer

I think the answer is that emulating classes in javascript is not the common practice, because the language is actually prototypal.

Although it is possible to create class like structures (as in your example), they are not really like java classes, and as a programmer, you end up fighting with the nuances.

If however, you embrace the prototypal nature of javascript, you are rewarded by a different, yet cohesive, and simple structure for the language.

It is not necessary to use getters and setters with prototypal structure, as you can simply set an object by, well, setting it to a value, and get it by, calling it as a value.

Javascript does not force you to write structured code, and does not stop you from doing so. I think the culture that has grown up around javascript has developed a good coding style, that is perfectly valid, and different from any other language I use.

I know this answer is not definitive, and conclusive, but hopefully there are some ideas in there that help you to find the anser you are looking for.

Answer

I apologize if I dont understand the question correctly, but self executing functions are one way to make members public/private

var Person = function(){
  var _name = "Roger",
      self = { getName : function (){ return _name; }};
  return self;
}()

You can then access Person.getName() from anywhere , but not set _name.

Answer

This is what I used for local fields:

TYPE_DEFAULT_VALUE= {
    number: 0,
    string: "",
    array: [],
    object: {},
};

typeOf = function (object) {
    if (typeof object === "number" && isNaN(object))
        return NaN;
    try {
        return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
    }
    catch(ex) {
        return "N/A";
    };
};

getAccessor = function(obj, key, type, defaultValue) {
    if (defaultValue === undefined) 
        defaultValue =  TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type];
    return {
        enumerable: true,
        configurable: true,
        get: function () {
            if (obj[key] === undefined) 
                obj[key] = defaultValue;
            return obj[key];
        },
        set: function (value) {
            if (typeOf(value) === type)
                obj[key] = value;
        },
    };
}

LocalFields = function (fields, object) {
    /**
    * field properties
    * { 
    *   type: [ required ] ( number | string | array | object | ... ),
    *   defaultValue: [ optional ]
    * }
    */
    if (! fields)
        throw "Too few parameters ...";
    if (! object) 
        object = this;

    var obj = this;
    var fieldsAccessor = {};
    for(key in fields){
        field = fields[key];
        fieldHandler = key[0].toUpperCase() + key.substr(1);
        if(! field.type)
            throw "Type not set for field: " + key;

        fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue)
    }
    Object.defineProperties(object, fieldsAccessor);
}

Now for each Class I can just call something like:

Person = function(){
    new LocalFields({
        id:     { type: "number" },
        name:   { type: "string" },
    }, this);
}

And then like VS getter and setter you'll call:

var alex = new Person();
alex.Name = "Alex Ramsi";
console.clear();
console.info(alex.Name);

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.