Отличные альтернативы __defineGetter__?

Getters and setters - это красота в VB.Net:

Get
    Return width
End Get
Set(ByVal value As Integer)
    width = value
End Set

В Javascript это, вероятно, то, что мы будем делать:

function Test() {
    var width = 100;
    this.__defineGetter__("Width", function() {
        return width;
    });
    this.__defineSetter__("Width", function(value){
        width = value;
    });
}

Похоже на тарелку спагетти, разграбленную кури. Какие альтернативы у нас есть?

Примечание. Новый код должен получить доступ к значению с помощью new Test().Width, а не new Test().Width().

Ответ 1

С ES5 вы сможете:

function Test() {
  var a = 1;

  return {
    get A() { return a; },
    set A(v) { a = v; }
  };
}

Функции getter/setter могут, конечно, делать все, что вы хотите.

Ответ 2

Здесь используется чистая альтернатива (также для более старых script):

function Test() {
  var a=1;
  return { A: { toString: function(){return a;} } };
}

alert(Test().A); //=> 1

Помните, вы не можете использовать его для определения частных/статических сложных структур. Вы можете только "получить" строки или цифры (такие неизменяемые переменные) с помощью этого шаблона. Возможно, шаблон можно улучшить с помощью json.

[ edit] Используя json, вы также можете создать getter для объектов:

function Test() {
  var a=1,
  b = {foo:50, bar:100};

  return { 
          A: { toString: function(){return a;} } 
          foobar: { toString: function(){return JSON.stringify(b);}  } 
         };
}
var foobar = JSON.parse(Test().foobar);
alert(foobar.foo); //=> 50

Ответ 3

В Ecmascript5 "чистый" (и совместимый со стандартами) способ сделать это - defineProperty.

function Test() {
    var a = 1;
    Object.defineProperty(this, "A", {get : function() { 
            return a;
        },  
        enumerable : true});
}

Это предполагает, что вы просто хотите посмотреть, как определить геттер. Если все, что вы хотите сделать, это сделать экземпляры Test неизменяемыми (что хорошо делать, где вы можете), вы должны использовать для этого замораживание:

function Test() {
    this.a = 1;
    Object.freeze(this);
}