Создание метода get / set динамически в JavaScript - PullRequest
6 голосов
/ 11 апреля 2010

Я пытаюсь создать объект UserDon и пытаюсь сгенерировать методы get и set программно (на основе книги Pro Javascript Джона Ресига, стр. 37), и я тестирую это в Firefox 3.5

Проблема в том, что в функции UserDon «this» относится к объекту окна, а не к объекту UserDon.

Итак, после вызова var userdon = new UserDon (...) я получил методы setname и getname, созданные для объекта window (также setage и getage).

Как я могу это исправить?

function UserDon( properties ) {
   for( var i in properties ) {
   (function(){
      this[ "get" + i ] = function() {
        return properties[i];
      };

      this[ "set" + i ] = function(val) {
        properties[i] = val;
      };
      })();
   }
 }

var userdon = new UserDon( {
   name: "Bob",
   age: 44
});

Ответы [ 4 ]

7 голосов
/ 11 апреля 2010

Используемое вами значение this относится к выражению функции автоматического вызова, которое у вас внутри цикла, и когда вы вызываете функцию таким образом, this будет всегда обращаться к глобальному объект.

Редактировать: Я пропустил тот факт, что выражение функции пытается сделать захват переменной для обработки создания геттера / сеттера внутри цикла, но переменной цикла i, для этого нужно передать в качестве аргумента, и поскольку здесь есть выражение функции, контекст (внешний this) должен быть сохранен:

function UserDon( properties ) {
  var instance = this; // <-- store reference to instance

  for( var i in properties ) { 
    (function (i) { // <-- capture looping variable
      instance[ "get" + i ] = function() {
        return properties[i];
      };

      instance[ "set" + i ] = function(val) {
        properties[i] = val;
      };
    })(i); // <-- pass the variable
  }
}

var userdon = new UserDon( {
   name: "Bob",
   age: 44
});

userdon.getname(); // "Bob"
userdon.getage();  // 44

Вы также можете использовать метод call для вызова выражения функции, сохранения контекста (значение this) и введения циклической переменной в новую область за один шаг:

function UserDon( properties ) {
  for( var i in properties ) { 
    (function (i) { // <-- looping variable introduced
      this[ "get" + i ] = function() {
        return properties[i];
      };

      this[ "set" + i ] = function(val) {
        properties[i] = val;
      };
    }).call(this, i); // <-- preserve context and capture variable
  }
}

Я бы также рекомендовал использовать if (properties.hasOwnProperty(i)) { ... } внутри цикла for...in, чтобы избежать перебора пользовательских расширенных свойств, унаследованных от Object.prototype.

1 голос
/ 11 апреля 2010

Вы также можете использовать менее известные
__defineGetter__("varName", function(){});
и __defineSetter__("varName", function(val){});

Хотя они нестандартные [например, x-html-replace content-type], они поддерживаются большинством браузеров, отличных от ie, т.е.

Синтаксис будет:

benjamin = new object();
benjamin.__defineGetter__("age", function(){
  return 21;
});

Или вы можете подойти к этому с помощью прототипа

benjamin = {
  get age()
  {
    return 21;
  }
}
0 голосов
/ 11 апреля 2010

Вот как бы я это закодировал: -

function UserDon( properties ) {
   var self = this;
   for( var i in properties ) {
   (function(prop){
      self[ "get" + prop ] = function() {
        return properties[prop];
      };

      self[ "set" + prop ] = function(val) {
        properties[prop] = val;
      };
      })(i);
   }
 }
0 голосов
/ 11 апреля 2010

Лучше получить обобщенную функцию с двумя параметрами: именем свойства и значением (или только именем для получателя). И эта функция будет проверять наличие специальной функции для этого свойства, а если ее нет, будет оправдано изменение значения свойства (или возврат его значения для метода получения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...