Создание метода get/set динамически в javascript
Я пытаюсь создать объект UserDon и пытаюсь генерировать методы get и set программно (на основе Pro Javascript book by John Resig page 37), и я тестирую это на Firefox 3.5
проблема в том, что в функции UserDon "это" относится к объекту window вместо объекта 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 ответов
на this
значение, которое вы используете, принадлежит выражению функции автоматического вызова, которое у вас есть внутри цикла, и когда вы вызываете функцию таким образом,this
будет всегда обратитесь к глобальному объекту.
Edit: я пропустил тот факт, что выражение функции попытка чтобы сделать захват переменной для обработки создания геттера / сеттера внутри цикла, но переменной цикла 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
.
вы также можете использовать малоизвестных__defineGetter__("varName", function(){});
и __defineSetter__("varName", function(val){});
хотя они не являются стандартными [как x-html-заменить content-type] они поддерживаются большинством браузеров не ie там [chrome, firefox]
синтаксис такой:
benjamin = new object();
benjamin.__defineGetter__("age", function(){
return 21;
});
или вы можете подойти к этому с прототипирования
benjamin = {
get age()
{
return 21;
}
}
было бы лучше получить общую функцию с 2 параметрами : именем свойства и значением (или только именем для геттера). И эта функция будет проверять наличие функции speial для этого свойства, и если ее нет, она просто изменит значение свойства (или вернет его значение для геттера).
вот как я бы его закодировал: -
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);
}
}