0

This is probably a basic question, and I am aware that there have been some similar questions around here, but still I did not find an answer. Please consider the following code:

function Outer(inner2) {
  var x = 5;
  this.inner1 = function() {return (x);}
  this.inner2 = inner2.bind(this);
}
var outer = new Outer(function() {return (x);});
alert(outer.inner1()); // works
alert(outer.inner2()); // does not work

If I would replace the second line by this.x = 5;, the second alert would work. So I guess the problem is that x when declared with var is not part of this, so that bind will have no effect.

Is there any way to make this work without using this.x?

11
  • x when declared with var is not part of this - correct. Commented Feb 9, 2018 at 0:13
  • 1
    You can't. There's no way JavaScript can know you're referring to a local variable inside the constructor while outside it unless you attach it to this or lift it out somehow. Commented Feb 9, 2018 at 0:13
  • 1
    If you do not want to expose your local variable with this.x, you might want to pass it as an argument to your inner2 method : var outer = new Outer(function (x) { return (x); }); and this.inner2 = inner2.bind(this, x) Commented Feb 9, 2018 at 0:20
  • @Li357 True at declaration time, but note that I never call the anonymous function given as parameter directly but only outer.inner2(). So, the compiler could infer the context. Commented Feb 9, 2018 at 0:21
  • @Flo-Schield-Bobby But then I had to change the signature of the anonymous function (add a parameter). Further, in reality, there are a lot of variables such as x, and I do not want to pass each of them... Commented Feb 9, 2018 at 0:23

3 Answers 3

1

Is there any way to make this work without using this.x?

No.

Btw, you probably don't even need to use bind, just calling inner2 as a method on the object would suffice when both the constructor and the method use this.x.

If you don't want to make x a property of the object, but keep it as a local variable, the usual strategy would be to pass it to the callback as an argument, not trying to somehow make it available in its scope implicitly:

function Outer(callback) {
  var x = 5;
  this.inner1 = function() { return x; };
  this.inner2 = function() { return callback(x); };
//                                          ^^^
}
var outer = new Outer(function(y) { return y; });
//                             ^           ^
alert(outer.inner1()); // works
alert(outer.inner2()); // works
Sign up to request clarification or add additional context in comments.

Comments

1

I think you need clarification on what the word "this" is referring to.

"this" is not pointing to the function "Outer."

When you invoke a constructor function with the "new" keyword, a few things happen.

  1. The constructor function returns an object.
  2. The "this" variable is changed, so that it is set to point to that object that is returned.
  3. (Also, the .proto of the object returned is set to the .prototype of the constructor function, but that step is not relevant here).

So, you are binding the callback function to the object that you are returning from the constructor function, not the constructor function itself.

Thus, the callback function is bound to outer (with a lower-case), not outer (with an upper-case).

Also, when you bind, you are not binding to the scope of a function. X is not assigned to any property. I think you only can bind to an object and access its properties with this.a etc.

The x in the first function worked because its value was assigned in the scope of the function.

1 Comment

Thanks, this was helpful in understanding this
0

I found an, albeit ugly, solution:

function Outer(inner2) {
  var x = 5;
  this.inner1 = function() {return (x);}
  eval('this.inner2 = ' + inner2.toString());
}

This works and shows my point: the parameter inner2 is just a prescription of how this.inner2 should look like; it is never invoked itself.

Let me know, if you have a neater solution than this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.