Using bind to enforce the context of a prototype function

I am working on JavaScript code that will be used to create constructors for "classes" (specifically Model Viewer) for our enterprise software. One of the things I do is create a design pattern using code where the developer will explicitly define what functions they want to expose with an instance of the class, and the code will add them to the constructor's prototype

constructor, as opposed to the properties of each instance of the class. This, of course, has the advantage that only one instance of each of these functions per type, as opposed to an instance for each instance.

Here's the CodePen of most of my examples.

The problem is that under certain conditions I am dealing with bug binding issues . For example, using this constructor:

  function Foo(myName) {
    this.firstName = myName;
  }

  Foo.prototype.greet = function(yourName) {
    alert("Hello, " + yourName + ". I am " + this.firstName + ".");
  }

      

... this will work:

var sam = new Foo("Sam");
// Alerts "Hello, Denny. I am Sam."
sam.greet("Denny");

      

... but it won't:

var sad = new Foo("Sad");
// This changes the context of greet. :(
var sadGreet = sad.greet;
// Alerts "Hello, Denny. I am undefined."
sadGreet("Denny");

      

This is because when we do var sadGreet = sad.greet

, we change the context of the function greet

to window

, therefore this.firstName

does not exist when called sadGreet("Denny")

.

So, the solution I came across was to overwrite the prototype with a property that calls that prototype, assuring it to Function.prototype.bind()

function Bar(myName) {
  this.firstName = myName;
  // Here where the magic happens.
  this.greet = Bar.prototype.greet.bind(this);
}

Bar.prototype.greet = function(yourName) {
  alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}

var happy = new Bar("Happy");
// Since each instance of Bar overwrites the context for greet, this will work. :)
var happyGreet = happy.greet;
// Alerts "Hello, Denny. I am Happy."
happyGreet("Denny");

      

My question is this: I'm guessing Bar

not as efficient as Foo

, but does this completely invalidate the benefit of declaring greet

as a method prototype

? Under the covers is it just duplication greet

as properties anyway, or is my call bind

just adding a "wrapper" for Bar.prototype.greet

? In other words, is it efficiently the same as the above definition for Bar?

function Bar(myName) {
  this.firstName = myName;
  // Here where the magic happens.
  this.greet = function(yourName) {
    alert("Hello, " + yourName + ". I am " + this.firstName + ".");
  }
}

      

Bonus points if you can't answer just a question, but tell me how to check it!

+3


source to share


1 answer


Bar is definitely less efficient than Foo, but not in terms of time complexity. Instead, it is less efficient in terms of memory consumption, since each Bar instance will now have a UNIQUE object and a NEW 'greet' (the 'bind' function creates a new function object).

Looking at your code it actually gets a bit confusing, even for the welcome function on Bar.prototype. Instead, this also works:

function Bar(myName) {
  this.firstName = myName;
  this.greet = greet.bind(this);
}

var greet = function(yourName) {
  alert("Hello, " + yourName + ". I am " + this.firstName + ".");
};

var happy = new Bar("Happy");
var happyGreet = happy.greet;
happyGreet("Denny");

      



You can check that the "welcome" function is not identical to the "greet" function of each instance, just try this:

console.log( greet === happyGreet );

      

+1


source







All Articles