Замыкания, что не так?

В книге "javascript, профессиональные приемы программирования" есть конструктор :
function User( properties ) {

for ( var i in properties ) { (function(){

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

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


var user = new User({
name: "Bob",
age: 44
});


Когда вызываю user.getname() выдает ошибку .. очень долго думая почему ето не работает , я визвал етот метод так , getname.call(user) и всё работает ...
Объясните пожалуйста , что хотел сказать автор . и почему это работает так getname.call(user) , но так user.getname() не работает
  • Вопрос задан
  • 2436 просмотров
Решения вопроса 3
lexxpavlov
@lexxpavlov
Программист, преподаватель
Проблема в том, что присвоение this[ "get" + i ] = function() {} происходит в анонимной функции, которой не присвоен контекст. Значит, контекстом является глобальный объект.
В данном случае геттеры и сеттеры создаются не у создаваемого объекта, а у глобального объекта (в браузере это window), поэтому вы вообще можете запустить функцию getname(). Её просто нет у объекта, но она есть в глобальном пространстве.
Чтобы исправить, нужно в конструкторе в начале сделать ссылку на this и присваивать геттеры/сеттеры объекту через эту ссылку, а не через ключевое слово this.
function User( properties ) {
    var user = this;
    for ( var i in properties ) { 
        (function(){
            user[ "get" + i ] = function() {
                return properties[i];
            };
            user[ "set" + i ] = function(val) {
                properties[i] = val;
            };
       })(); 
    }
}

Верно отметил @Fesor в соседнем ответе, лучше не плодить переменные, если можно указать контекст вызова явно:
function User( properties ) {
    for ( var i in properties ) { 
        (function(){
            this[ "get" + i ] = function() {
                return properties[i];
            };
            this[ "set" + i ] = function(val) {
                properties[i] = val;
            };
       }).call(this); 
    }
}
Ответ написан
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
ну начнем с того что лучше так вообще не делать, геттеры/сеттеры так же надо либо выносить в прототип либо использовать defineGetter/setter.

А не работает потому что у вас внутри геттеров и сеттеров не тот контекст. То есть вы должны либо использовать у замыкания метод bind и привязать их к вашему объекту, либо указывать ссылку на this в конструкторе (не очень хорошо).
Ответ написан
leahch
@leahch
3D специалист. Dолго, Dорого, Dерьмово.
Оператор this яваскрипте не всегда указывает на то, на что хотелось бы. Вот javascript.ru/Function/call и вот habrahabr.ru/post/199456 на почитать. А всё потому, что в яваскрипте объекты, как таковые, не совсем объекты. Я так вообще this стараюсь не применять, ибо странный он...
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы