Вчера натолкнулся на некую особенность в переопределении геттеров и сеттеров в цикле.
Вот пример кода. Я не нашел явного ответа на ситуацию. Если кто поможет, то буду рад.
function Obj(){
this.a = 10;
this.b = 20;
for( ident in this ){
Object.defineProperty(this, ident , {
get : function(){
return ident ;
}
})
}
return this;
}
var a = new Obj();
console.log( a.a , a,b )
Логично предположить, что результатом будет «a» и «b». Я тоже так думал, но к сожалению ответ будет «b» и «b».
Затем я убрал циклы
function Obj(){
this.a = 10;
this.b = 20;
Object.defineProperty(this, 'a' , {
get : function(){
return 'a';
}
})
Object.defineProperty(this, 'b' , {
get : function(){
return 'b';
}
})
return this;
}
var a = new Obj();
console.log( a.a , a.b )
Результат оказался предсказуем — «a» и «b».
Я не знаю как описать такое поведение, но решается довольно просто —
function Obj(){
this.a = 10;
this.b = 20;
Object.keys(this).map(function(__prop){
Object.defineProperty(this, __prop , {
get : function(){
return __prop;
}
})
},this)
return this;
}
var a = new Obj();
console.log( a.a , a.b )
Получим «a» и «b».
Если кто в комментариях сможет описать причину, то дополню статью.
Комментарии (5)
AndreyRubankov
03.10.2016 10:24+1Если по быстрому и по простому: замыкание берет «ссылку» на переменную (а не ее значение).
Следовательно, когда эта переменная изменяется (в цикле) то и в замыкании значение будет другим (в случае с циклом всегда будет последнее значение). Грубо говоря, в вашем случае на все геттеры всего одна функция, а не N, как вы ожидали.
Если сильно хочется, можете попробовать такой вариант:
(function (value) { return function () { return value; } })(ident)
ertaquo
03.10.2016 10:25Во-первых, с вопросами вам на Toster надо.
Во-вторых, вы действительно не знаете основы языка, как подметил vintage. Геттер в вашем случае всегда будет использовать текущее (на момент вызова) значение переменной цикла. Так как он вызывается после окончания цикла, то берется последнее значение, т. е. b.
Чтобы избежать этого, можно обернуть итерацию цикла в функцию, либо использовать bind().
vintage
Лучше удалите статью, пока вам не слили карму за не знание основ. Почитайте любой учебник по яваскрипту, главу про замыкания. Внимательно.
Fr3nzy
Ну и ссылка вдогонку на эту тему (ответ, конечно же, не полный): http://stackoverflow.com/a/750506