简体   繁体   中英

How to create proper closures in jQuery?

This is an example of my code:

var bar = function() {

  this.baz = function() {
    this.input = $('.input');
    this.input.bind("keydown keyup focus blur change", this.foo);
  }

  this.foo = function(event){
    console.log(this);
  }

}

Clicking on my input gives me the input in the console, obviously. How can i get bar as this instead?

That happens because when you bind an event, the event handler function is called with the context of the DOM element which triggered the event, the this keyword represents the DOM element.

For getting "bar" you should store a reference to the outer closure:

var bar = function() {
  var self = this;

  this.baz = function() {
    this.input = $('.input');
    this.input.bind("keydown keyup focus blur change", this.foo);
  }

  this.foo = function(event){
    console.log(this); // the input
    console.log(self); // the bar scope
  }
};

Note: If the bar function is called without the new operator, this will be the window object and baz and foo will become global variables, be carefull!

However I think your code can be simplified:

var bar = {
  baz: function() {
    var input = $('.input');
    input.bind("keydown keyup focus blur change", this.foo);
  },

  foo: function(event){
    console.log(this); // the input
    console.log(bar); // reference to the bar object
  }
};

to get bar in your foo do this:

bar = function() {

var me = this;

this.baz = function() {
    this.input = $('.input');
    this.input.bind("keydown keyup focus blur change", this.foo);
}

this.foo = function(event){
    // me, would be your bar object.
    console.log(me);
}

}

This is a general problem when using instance methods as callbacks in JavaScript. I use this function to create a closure to call the method bound to the correct instance:

function bound_method(instance, method) {
  return function() {
    return method.apply(instance, arguments);
  };
}

Then you can use this as your callback in place of this.foo:

bound_method(this, this.foo)

Unlike some of the other proposals, this allows you to put the methods on the prototype instead of creating them in the constructor. This way you only have one shared copy of the implementation instead of re-creating those functions for each new instance of bar.

var bar = function() {};
$.extend(bar, {
  baz: function() {
    this.input = $('.input');
    this.input.bind("keydown keyup focus blur change",
                    bound_method(this, this.foo));
  },

  foo: function(event) {
    console.log(this);
  }
});

Here you go.this is an exmaple of how to get "this"

<html>
<head></head>
<script  type="text/javascript" src="jquery-1.3.2.min.js"></script>

<script>
 var  bar = function() {

this.baz = function() {
    this.input = $('.input');
    this.input.bind("keydown keyup focus blur change", this.foo);
}

this.foo = function(event){
    console.log(this);
}

}

</script>
<body>
<input class="input">
<button onclick="new bar().baz()">Click</button>
</body>
</html>

This happens because the function baz is called with an instance of bar.SO bar is executing within the "new bar()" context and not the window object.

If you are using firebug (it seems so), you can track the logging as you type inside the input text control before and after clicking the click within the console tab.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM