1

I've created the following object:

function Calculator() { 
    //some code here, including object variables and functions, such as:
    this.add = function(x) {
       //again, irrelevant code
    }
    //similar methods
}


var calc = new Calculator();

And then, I tried to do the following:

var met = calc.add;
met(5);

But it didn't work.

(I've checked everything - the variable 'met' is of type 'function', when I "alert" it to be certain, it alerts the proper string - function(x){...}, etc. But calling met(7) does nothing, while calling calc.add(7) adds the number)

Does anyone know why, or how can I fix it? (Can I fix it?)

Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
Udi
  • 43
  • 1
  • 7
  • 2
    You _say_ the function body of the `add` method is irrelevant, but just to be safe: can you include it here anyway? if you're accessing closure vars, or object properties then that's your problem... anyway, the way you're calling the method does imply that the method relies on other properties of the object – Elias Van Ootegem Nov 22 '12 at 20:59
  • This might be a scoping issue (http://stackoverflow.com/questions/3127429/javascript-this-keyword). Post some actual code. – Waleed Khan Nov 22 '12 at 21:02
  • What browser (or environment if server side) are you using? – psema4 Nov 22 '12 at 21:13
  • @EliasVanOotegem: It turns out, it did access object properties, and combined with what is written below (regarding "this" and context), that was the problem. Thanks for the help! – Udi Nov 22 '12 at 21:27

4 Answers4

1

Actually, the function inside add is not irrelevant. The problem you're having is because how this behaves in javascript.

When you call it like this:

met(5);

it's the same as doing it like this:

window.met(5); // assuming browsers

Which means that the this in met is bound to the global object. So the reason it doesn't work is because whatever variable you're trying to add to doesn't exist in the global object. You can test it simply by declaring that variable in the global object (which for browsers happen to be global variables):

var foo = {
    i = 0,
    incr = function(){ return ++this.i }
}
foo.incr(); // this works as expected

// now assign foo.incr to the global object:
var inc = foo.incr;
inc(); // this fails because window.i doesn't exist

// create i in window
i =0;
inc(); // now this works, maybe a bit unexpected

If you want to simply alias add to met but still operate on the calc object you have two options. The first is to make sure that add is called as a method of calc:

var met = function(x) { return calc.add(x) };
met(5);

This is simple and it works as expected. By adding an anonymous function wrapper we can call add as calc.add() which makes this bound to calc.

The second is as mentioned by @Guffa: use call or apply to point this to whatever you want:

var met = calc.add;
met.call(calc,5);

To understand more about how this works in javascript read this: How does the "this" keyword in Javascript act within an object literal?

Community
  • 1
  • 1
slebetman
  • 93,070
  • 18
  • 116
  • 145
  • A slightly simpler way of making met be calc.add in modern browsers is ``var met = calc.add.bind(calc);``. Another option (although I don't like it), is to define this.add so that internally it doesn't use this, but uses some other variable like 'mycalc', which is closed over - i.e. above this.add's definition in the constructor, you would write ``var mycalc = this;``, and then anywhere you would refer to this inside add, use mycalc instead. This is not a great way of defining objects, but lets you easily pass them around as functions without worrying about them detaching from their object. – kybernetikos Nov 22 '12 at 22:34
0

When you get a reference to a method, you just get the function, it's not connected to the object any more. If you call the function, this is no loger a reference to the object, it's the global window object, that's why the code in the function no longer works.

To call it as a method, you need to make the call specifying that it should run as a method of the object:

met.call(calc, 5);
Guffa
  • 640,220
  • 96
  • 678
  • 956
0

It works. You don't have the problem you think you have.

function Calculator() { 
    //some code here, including object variables and functions, such as:
    this.add = function(x) {
       alert('bob');
    }
    //similar methods
}

var met = new Calculator().add;

met();//'bob'

You're probably running into some kind of a scope issue as others have suggested. met should have access to any var established above the add method.

Erik Reppen
  • 4,427
  • 20
  • 25
0

What you have to remember is that every time a function is called it is as if this is a hidden parameter and not something that is set when you call the function and saved in the function's closure.

When you call met(5) the following will be output to the console:

function Calculator() {
    y = 10; // set variable

    this.add = function(x) {
       console.log( this.y ); // => undefined as window object does not have y
       console.log( y ); // => 10 as function can access parent function's closure

       function printY( ) {
            console.log( y ); // => undefined as this function can only access parent function's closure and that does not contain a y variable.
       }
    }
}
Bruno
  • 5,504
  • 1
  • 22
  • 39