Я пытаюсь создать объект UserDon, и пытающийся генерировать получение и методы установки программно (на основе Pro книги JavaScript страницей 37 John Resig), и тестирую это на Firefox 3.5
Проблема: в функциональном UserDon "это" относится к объекту окна вместо объекта UserDon.
Таким образом, после называния var userdon = новый UserDon (...) я получил setname и getname методы, созданные на объекте окна (также 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
});
Используемое вами значение 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
.
Вот как я бы это закодировал: -
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);
}
}
Возможно, было бы лучше получить общую функцию с 2 параметрами: имя свойства и значение (или только имя для геттера). И эта функция проверяла бы наличие специальной функции для этого свойства, и если таковой нет, то просто изменяла бы значение свойства (или возвращала бы его значение для getter).
Вы также можете использовать менее известные
__ defineGetter __ ("varName", function () {});
и __ defineSetter __ ("varName", function (val) {});
Хотя они нестандартны [например, x-html-replace content-type], они поддерживаются большинством браузеров, не относящихся к IE [chrome, firefox]
Синтаксис будет следующим:
benjamin = new object();
benjamin.__defineGetter__("age", function(){
return 21;
});
Или вы можете подойти к этому с прототипированием
benjamin = {
get age()
{
return 21;
}
}