3

I have following Javascript objects:

function Alfa() {
  this.status='';
  this.setStatus = function(value) {
    this.status=value
  }
}

function Beta() {
  this.setSomething = function(setter) {
    setter('Something');
  }
}

And than execution:

alf=new Alfa();
alf.setStatus('foo');

This works fine, if you look into values of alf, the status is set to 'foo', but:

bet=new Beta();
bet.setSomething(a.setStatus);

What I have expected is that bet will execute setStatus function of alf and set status value to 'something', however, this is not happening. setStatus of alf is executed, but this points not to alf instance but to Window, so the property status is set for Window not for alf.

What is the proper approach to get desired functionality?

This is of course simplified implementation, in real life i want to pass those functions of alf to event handlers, so I cannot change Beta implementation, eg:

$('xxx').click(alf.setStatus)
1
  • I can at least one error: you pass a.setStatus to bet.setSomething() but where is a declared? Commented Jan 22, 2012 at 13:44

4 Answers 4

4

JavaScript functions are unbound. That means this is determined by how it's invoked rather than how it was defined. Because you are invoking the method from within bet, then this is bet

To get around this you need to make a bound function, which creates a stable this no matter how the function is invoked.

If you are using an ES5 compatible JavaScript interpreter then you can use: Function.bind

alf.setStatus.bind(alf)

Or if you arent there are several es5 shims that provide this functionality in older interpreters. In fact one is provided on the mdn reference for bind. JQuery has a version called $.proxy

A simple implementation is that you want a function that takes a function and a scope. And then calls your method in that scope specifically, rather than using this. Something like.

function bind(func,o) { return function() { func.call(o); } }
Sign up to request clarification or add additional context in comments.

3 Comments

the correct would be alf.setStatus.bind(alf), as the syntax is fn.bind(context)
Yes sorry. I'm on the train and trying to type this on my phone. Auto correct also got my a few times. Making an edit.
+1 for mentioning $.proxy, as I usually use underscore.js _.bind()
1

Change setter('Something'); to setter.call(this, 'Something'); will be work.

1 Comment

"so I cannot change Beta implementation"
1
function Alfa() {
    this.status='';
    this.setStatus = function(value) {
        this.status=value
    }
}
function Beta() {
    this.status='';
    this.setSomething = function(setter) {
        setter.call(this,'Something');
     }
}

Comments

1

Functions in JavaScript don't have a context attached to them, like e.g. bound methods in Python. So what you can do is to call setStatus functions with a context, like this:

bet.setSomething(function(value) {
    a.setStatus.call(a, value);
});

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call

2 Comments

"so I cannot change Beta implementation"
And additionally this reduces the functionality of Beta objects (as it has to know that there is method setStatus of alfa objects) So not the best idea

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.