开发者

Best way to create class getter/setters in Javascript?

Coming from C#/PHP, I would like to have full getters/setters on the classes (functions) that I create with Javascript.

However, in much of the Javascript code I have encountered, getters and setters are not used, rather simple public variables.

I was pleased to find John Resig's article on getters and setters, but some comments on it which state that some browsers "do not support getters and setters" which is confusing to me since they are not a "feature" of Javascript but more of a simple pattern which uses basic Javascript syntax. This article was also written in 2007 so it could be outdated by now.

What is the current state of getters and setters in Javascript? Are they indeed "supported" by all browsers today (whatever that means)? Are they a useful programming pattern for Javascript or are Javascript classes (being functions) better off with public variables? Is there a better way to implement them than the following?

$(document).ready(function() {
    var module = new Module('idcode');
    module.set_id_code('new idcode');
    module.set_title('new title');
    $('body').html(module.get_id_code()+': '+module.get_title());
});

function Module(id_code, title) {
    var id_code = id_code;
    var title = title;

    //id_code
    this.get_id_code = function() {
        return id_c开发者_如何转开发ode;
    }
    this.set_id_code = function(value) {
        id_code = value;
    }

    //title
    this.get_title = function() {
        return title;
    }
    this.set_title = function(value) {
        title = value;
    }
}


Firefox, Safari, Chrome and Opera (but not IE) all have the same non-standard getter and setter mechanism built in. ECMAScript 5 includes a different syntax that is currently making its way into browsers and will become the standard in future. IE 8 already has this feature, but only on DOM nodes, not regular native JavaScript objects. This is what the syntax looks like:

var obj = {};

Object.defineProperty(obj, "value", {
    get: function () {
        return this.val;
    },
    set: function(val) {
        this.val = val;
    }
});


You're missing the point, I think. (Or maybe the other answerers are missing the point.) ECMAScript provides a "behind-the-scenes" getter/setter mechanism, so that

x.foo = 3;
y = x.foo;

really translates into (sort of)

x.PutValue("foo",3);
y = x.GetValue("foo");

where PutValue and GetValue are unnamed, not directly accessible functions for setters and getters for properties. (See the ECMAScript standard, 3rd ed., section 8.7.1. and 8.7.2) The 3rd edition doesn't seem to explicitly define how users can set up custom getters and setter functions. Mozilla's implementation of Javascript did and still does, e.g. (this is in JSDB which uses Javascript 1.8):

js>x = {counter: 0};
[object Object]
js>x.__defineGetter__("foo", function() {return this.counter++; });
js>x.foo
0
js>x.foo
1
js>x.foo
2
js>x.foo
3
js>x.foo
4

The syntax is (or at least has been so far) browser-specific. Internet Explorer in particular is lacking, at least according to this SO question.

The 5th edition of the ECMAScript standard does seem to standardize on this mechanism. See this SO question on getters and setters.


edit: A more practical example, perhaps, for your purposes:

function makePrivateObject()
{
   var state = 0;
   var out = {};
   out.__defineSetter__("foo", function(x) {});
   // prevent foo from being assigned directly
   out.__defineGetter__("foo", function() { return state; });
   out.count = function() { return state++; }
   return out;
}

js>x = makePrivateObject()
[object Object]
js>x.foo
0
js>x.foo = 33
33
js>x.foo
0
js>x.count()
0
js>x.count()
1
js>x.count()
2
js>x.foo
3


How about:

function Module(id_code, title) {
    var id_code = id_code;
    var title = title;

    var privateProps = {};

    this.setProperty = function(name, value) {
      // here you could e.g. log something
      privateProps[name] = value;
    }

    this.getProperty = function(name) {
      return privateProps[name];
    }
}

The getter and setter methods here act on a private object used to store properties that cannot be accessed from any other methods. So you could, for example, implement a setter (or getter) that logs or does ajax or whatever, whenever a property is modified (one of the purposes of getter/setter methods).


You can actually define setters and getters in javascript and not just mimick them. I think it works on every browser except IE8 and below.

$(document).ready(function() {
  var module = new Module('idcode');
  module.id = 'new idcode';
  module.title = 'new title';
  $('body').html(module.id + ': ' + module.title);
});

function Module(id, title) {
  return {
    id_code: id_code,
    _title: title,

    get id() {
      return id_code;
    },
    set id(value) {
      id_code = value;
    },

    get title() {
      return _title;
    },
    set title(value) {
      title = value;
    }
  }
};


I like this :

//  Module
var Module = function() {

    // prive getter/setter value
    var __value;

    // private getter/setter method
    var _value = function() {
        if(!arguments.length) return __value;
        else __value = arguments[0];
    };

    // output/public     
    return {
        value: _value
    };
}


Getters and setters aren't features, but "design patterns" (code bloat in this case) for languages that don't support property syntax.

Since Javascript doesn't need getters and setters, you don't want to write them. Use the language features that are available to you and idioms that work great in one languages don't work so well in another.

One of my favorite quotes comes from Python's community:

We're all consenting adults here

when discussing why private variables and information hiding isn't needed.

The quote can be found here.

Learn what the language offers you and embrace its culture and rules.


One reliable, semantic way I've favored is to use setters and getters. For example, I created the following object:

var myComplexObject = {
  changelog: {},
  log: function(name, val) {
    console.log("set " + name + " to " + val);
    if (!this.changelog[name])
      this.changelog[name] = [];
    this.changelog[name].push(val);
  },
  set o (val) {
    this.log("o", val);
  },
  get o () {
    console.log("You will never know the true value!");
    return 42;
  }
}

In here, whenever you read or modify the value of o, the behavior is customized. Take, for example, the following line of code and its console output:

myComplexObject.o = "oxygen";
set o to oxygen

Then, in this example, attempting to read the value results in this:

var read = myComplexObject.o;
console.log(read);
You will never know the true value!
42

And, in this example, each new value you set is logged:

myComplexObject.o = "Oh no!";
console.log(myComplexObject.changelog.o);
set o to Oh no!
["oxygen", "Oh no!"]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜