Почему эти две функции JavaScript не эквивалентны?
Эта функция работает:
function refreshCodeMirror(){
$("textarea").each(function(){
var codeMirror = $(this).data('codeMirror');
setTimeout(function(codeMirror){
return function () {
codeMirror.refresh();
}
}(codeMirror), 10)
});
}
Но когда я попытался упростить это до этого:
function refreshCodeMirror(){
$("textarea").each(function(){
var codeMirror = $(this).data('codeMirror');
setTimeout(codeMirror.refresh, 10)
});
}
Упрощение не работает.
Некоторый (возможно, не относящийся к делу) контекст:
Функция refreshCodeMirror вызывается в onclick для заголовка вкладки начальной загрузки в шаблоне django:
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs" role="tablist">
{% for field in form_tab_fields %}
<li role="presentation"{% if forloop.first %} class="active"{% endif %}>
<a class="tab-header" href="#{{ field.id_for_label }}_tab" data-toggle="tab" onclick="refreshCodeMirror()">{{ field.label_tag }}</a>
</li>
{% endfor %}
</ul>
<div class="tab-content">
{% for field in form_tab_fields %}
<div role="tabpanel"
class="form-group tab-pane{% if forloop.first %} active{% endif %}"
id="{{ field.id_for_label }}_tab">
{{ field }}
{{ field.errors }}
</div>
{% endfor %}
</div>
</div>
</div>
Все работает нормально с первой функцией выше, и, хотя я хотел бы удалить все избыточные вызовы обновления, они, кажется, не имеют значения, и когда я использую одну текстовую область (передавая идентификатор элемента), рабочая функция выше останавливается за работой.
1 ответ
Проблема в том, что вы теряете контекст.
Функции, которые не вызываются непосредственно в объекте и не связаны вручную с контекстом, вызываются в глобальном контексте.
var obj = {
print: function() {
document.write('<pre>' + this + '</pre>');
}
};
obj.print();
var p = obj.print;
p();
Когда вы используетеsetTimeout
или другие подобные функции, это как делать это:
function setTimeout(f, time) {
wait(time);
f();
}
Так что ваши refresh
функция ожидает this
быть равным вашему codeMirror
экземпляр, но вместо этого он равенwindow
или жеundefined
(в зависимости от того, находитесь ли вы в строгом режиме).
Есть несколько способов исправить это. Один из них - передать новую функциюsetTimeout
где вы вызываете свою первоначальную функцию.
setTimeout(function() {
codeMirror.refresh();
}, 10);
Другой способ, это использоватьbind
передать ему копию функции с this
установить на правильный объект.
setTimeout(codeMirror.refresh.bind(codeMirror), 10);