Why are these two javascript functions not equivalent?

馋奶兔 提交于 2019-12-08 12:37:21

问题


This function works:

function refreshCodeMirror(){
  $("textarea").each(function(){
    var codeMirror = $(this).data('codeMirror');
    setTimeout(function(codeMirror){
      return function () {
        codeMirror.refresh();
      }
    }(codeMirror), 10)

  });
}

But when I tried to simplify it to this:

function refreshCodeMirror(){
  $("textarea").each(function(){
    var codeMirror = $(this).data('codeMirror');
    setTimeout(codeMirror.refresh, 10)

  });
}

The simplification does not work.

Some (possibly irrelevant) context:

The refreshCodeMirror function is being called in the onclick for a bootstrap tab-header within a django template:

   <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>

Everything works fine with the first function above and, while I would like to remove all the redundant refresh calls, they don't seem to matter and when I use a single text area (by passing the element id), the working function above stops working.


回答1:


The problem is you lose the context.

Functions which are not called directly on an object and are not manually bound to a context, are called in the global context.

var obj = {
  print: function() {
    document.write('<pre>' + this + '</pre>');
  }
};

obj.print();
var p = obj.print;
p();

When you use setTimeout or other similar functions, it's like doing this:

function setTimeout(f, time) {
  wait(time);
  f();
}

So your refresh function is expecting this to be equal to your codeMirror instance but instead it's equal to the window or undefined (depending on if you're in strict mode).

There are a few ways to fix this. One is to pass a new function to setTimeout where you call your original function.

setTimeout(function() {
  codeMirror.refresh();
}, 10);

Another way, it to use bind to pass it a copy of the function with this set to the correct object.

setTimeout(codeMirror.refresh.bind(codeMirror), 10);


来源:https://stackoverflow.com/questions/37262818/why-are-these-two-javascript-functions-not-equivalent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!