3

A JavaScript newbie here. I have this following code:

function testObject(elem) {
    this.test = "hi";
    this.val = elem;
    console.log(this.test+this.val);
    echo();

    function echo () {
        console.log(this.test+this.val);
    }
}

var obj = new testObject("hello");

When it is run, I expect "hihello" to be outputted twice in the console. Instead it outputs as expected the first time but returns NaN the second time.

I'm sure I'm missing something here. I thought that the internal function can access the vars held outside. Can someone please guide me? I'm more of a functional UI developer and don't have much experience with OO code.

Thanks!

Newbie Coder
  • 55
  • 1
  • 4

3 Answers3

4

The problem is that inside echo the this value points to the global object, and this.test and this.val (which are referring to window.test and window.val) are undefined.

You can set the this value of echo by invoking it like:

echo.call(this);

That happens because you were invoking the function by echo();, then the this value is implicitly set to the global object.

Give a look to this question to learn how the this value works.

Edit: For being able to calling just echo(); you should persist the this value from the outer function context, there are a lot of ways to do it, for example:

//...
var instance = this; // save the outer `this` value
function echo (){
  console.log(instance.test+instance.val); // use it
}
echo();
//...

Or

//...
var echo = (function (instance) {
  return function () {
    console.log(instance.test+instance.val);
  };
})(this); // pass the outer `this` value
echo();
//...
Community
  • 1
  • 1
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • I think I'm getting the idea. What if the echo function takes parameters as well? echo("sometext").call(this) doesn't seem to work. – Newbie Coder Aug 03 '10 at 20:17
  • @Newbie: You can simply pass them after the first argument of `call`, e.g. `echo.call(this, 'arg1', 'arg2');` – Christian C. Salvadó Aug 03 '10 at 20:18
  • Thanks, this works but this also means that I'll have to change each and everyone of my function calls. Any way I can modify the function declaration itself to make it work? Thanks again! – Newbie Coder Aug 03 '10 at 20:25
  • @Newbie, to simply call `echo();` you should persist the `this` value from the outer function, I've added two exapmles... – Christian C. Salvadó Aug 03 '10 at 20:38
3

You could also do this:

function testObject(elem) {
    this.test = "hi";
    this.val = elem;
    console.log(this.test+this.val);

    this.echo = function () {
        console.log(this.test+this.val);
    }
    this.echo();
}

var obj = new testObject("hello");

​Whenever you call this.echo() or obj.echo(), this will be bound to the object invoking the function.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

Personally, I find it elegant to declare class methods like this:

function testObject(elem) {
    this.test = "hi";
    this.val = elem;
    this.echo();
}

testObject.prototype = {
    echo: function () {
        console.log(this.test + this.val);
    }
}

var obj = new testObject("hello");
jmc
  • 540
  • 3
  • 11