What is the rule for jQuery callback function $(this) context -


it seems context $(this) changes during circumstances class selector. spent number of hours trying debug below javascript, not at:

$.fn.specialbutton = function(callback) {     $(this).bind('click', function() { // $(this) a.button, expected         $.ajax({             url: 'ajax.php',             data: callback(); // context pitfall          }).done(function(response) {             $(this).html(response); // context changed unknown         })     }); }  $('a.button').specialbutton(function() {     // context pitfall      return {         id: $(this).data('id'); // $(this) not expect     }; }); 

eventually figure solution save context , use explicit calling of callback:

$.fn.specialbutton = function(callback) {     $(this).bind('click', function() { // $(this) a.button, expected          var $this = $(this); // save context;          $.ajax({             url: 'ajax.php',             data: callback.call($this); // explicitly specify context         }).done(function(response) {             $this.html(response); // reuse saved context         })     }); }  $('a.button').specialbutton(function() {     // context pitfall      return {         id: $(this).data('id'); // $(this) specified in prototype     }; }); 

what rule , reason change of context? design feature or limitation? not seem affect if selector html id selector i.e. $('a#button'). better or common way code above?

since mentioned article helped answer, ill try mention key points article,

in javascript, binding explicit, , can lost, method using not refer proper object in situations, unless force to. overall, binding in javascript not difficult concept, far ignored or glossed on javascripters, leads confusion.

example:

var john = {   name: 'john',   greet: function(person) {     alert("hi " + person + ", name " + this.name);   } }; john.greet("mark");  //=> "hi mark, name john" 

then again,

var john = {   name: 'john',   greet: function(person) {     alert("hi " + person + ", name " + this.name);   } }; var fx = john.greet; fx("mark"); // => "hi mark, name "  

this single important issue javascript binding—something i’ll refer “binding loss.” happens whenever you’re accessing method through reference instead of directly through owner object. method loses implicit binding, , stops referencing owner object , goes default value, in case window (so if window had name property then, used).

recognizing binding-sensitive code patterns

binding-sensitive code patterns involve passing method references, happens through 2 possible means: either you’re assigning method value, or you’re passing method argument (which same thing, when think it).

binding explicitly

so how fix it? bind explicitly—that is, explicitly state point within method when gets called. , how that? javascript provides 2 options: apply , call.

var fx = john.greet; fx.apply(john, ["mark"]); // => "hi mark, name john"   var fx = christophe.greet; fx.call(christophe, "mark"); // => "hi mark, name john" 

so want way persistently bind method, bound method reference, speak. way achieve requires wrap our original method in one, perform apply call. here’s stab @ it:

function createboundedwrapper(object, method) {   return function() {     return method.apply(object, arguments);   }; }  var john = {   name: 'john',   greet: function(person) {     alert("hi " + person + ", name " + this.name);   } }; var fx = createboundedwrapper(john, john.greet);  fx("mark"); // => "hi mark, name john"  

if you’re not keen on javascript, code above may confuse bit. idea here calling createboundedwrapper given object , method (which, presumably, belongs said object) produce brand new function (the anonymous 1 we’re returning).

should bind?

now we’ve been through details of binding, it’s fair stress sometimes, binding overkill. specifically, there’s code pattern in binding can replaced, significant performance profit, using lexical closure. (if you’re not clear on closure is, don’t panic.)

here’s pattern: code within method relies on anonymous function passed reference work. anonymous function needs access surrounding method’s keyword. instance, assuming minute have each iterator within arrays, consider following code again:

// ...   processitems: function() {     this.items.each(function(item) {       // process item…       this.markitemasprocessed(item);     });   }, // ... 

the anonymous method can wrapped around createboundedwrapper , inner this point outer scope's this.

however, such code not idea may seem. saw achieving such “bound reference” requires wrap original method within anonymous function, means calling bound method reference results in 2 method calls: our anonymous wrapper, , original method. , if there’s 1 thing true of language, it’s method calls costly.

in situation, have access original, desired keyword in same code location define , call faulty function (the anonymous method we’re passing argument each). can save proper reference in local variable, , use inside our iteration function:

// ...   processitems: function() {     var = this;     this.items.each(function(item) {       // process item       that.markitemasprocessed(item);     });   }, // ... 

takeaway points

to recap:

any member access must qualified object pertains to, when this. sort of function reference (assigning value, passing argument) loses function’s original binding. javascript provides 2 equivalent ways of explicitly specifying function’s binding when calling it: apply , call. creating “bound method reference” requires anonymous wrapper function, , calling cost. in specific situations, leveraging closures may better alternative. 

hope helps.


Comments

Popular posts from this blog

jquery - How can I dynamically add a browser tab? -

node.js - Getting the socket id,user id pair of a logged in user(s) -

keyboard - C++ GetAsyncKeyState alternative -