Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript bind to object

Tags:

javascript

function Developer(skill) {
    this.skill = skill;
    this.says = function() {
        alert(this.skill + ' rocks!');
    }
}
var john = new Developer('Ruby');
var func = john.says;
func();

I tried this example when I do this I get the following message undefined rocks! instead of Ruby rocks!. can u explain why is that.

like image 248
Lahiru Prasanna Avatar asked Oct 21 '25 15:10

Lahiru Prasanna


1 Answers

Function Execution Context and the this Keyword

JavaScript functions have an execution context at invocation time such that the this keyword is bound to the object they are invoked from. If you call john.says() the execution context of the function would have a this keyword that points to john. If you instead assign a global variable func to the method says found on the object john you have changed the execution context to the global object. When you invoke the func function, this dereferences to window (or undefined*) and since window.skill is undefined, says will coerce that value into a string to concatenate it with the string ' rocks!'.

How to guarantee execution context using bind

You can instead bind a copy of the function to an object (effectively locking it's context reference):

var func = john.says.bind(john);

How to guarantee execution context using a closure

Alternately you can close over the relevant bits by using a closure in your constructor:

function Developer(skill){
  var _this = this; // we keep a reference here
  this.skill = skill;
  this.says = function(){
    alert(_this.skill + ' rocks!'); 
    // when invoked _this refers to the context at construction
  }
  return this;
}

How to guarantee a value using a closure

You could just reference the skill value directly from the method and so not need the context at all:

function Developer(skill){
  // because skill is defined in this context, says will refer to this context
  // to get the value of the skill variable.
  this.says = function(){
    alert(skill + ' rocks!');
  }
}

How to guarantee an execution context at invocation time using call and apply

The final options are to to invoke the method with the context you want at invocation time:

func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);

How to use prototypes to allow the dynamic execution context to set the right this

If we want to reuse a method between object instances or types but have the right execution context when invoked we can use the prototype property.

function Developer(skill){
  this.skill = skill;
  this.says();
}

Developer.prototype.says = function(){
  alert(this.skill + ' rocks!');
}

var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript");  // alert("JavaScript rocks!")

More reading:

  • Specification for execution contexts: http://ecma-international.org/ecma-262/5.1/#sec-10.3
  • MDN Docs about this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Fthis

* "use strict" activates a special strict mode representing the future of JavaScript. This special strict executing environment will not resolve to the global object when a context has not been set, instead resolving this to the appropriately scoped value undefined.

like image 86
Gabriel Avatar answered Oct 23 '25 05:10

Gabriel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!