1

I'm breaking my head here. I have this simple code :

function myFunc()
{
    this.a = "aaa";

    return {
        h: function ()
        {
                   alert(this.a);
        }
    }
}



var f = new myFunc();
console.log(f.h.apply(f)) //I'm expecting to see here : "aaa" but it says "undefined"

f.h look exactly like this :

 function ()
 {
      alert(this.a);
     } 

And so , i'm trying to set context to f itself (which contains the a prop) via apply.

But it doesn't work.

What am I missing ?

p.s. there are other alternatives. I know. but why my specific code doesn't work ?

Royi Namir
  • 144,742
  • 138
  • 468
  • 792

5 Answers5

6

f does not contain a, since you return an arbitrary object that 'overwrites' the default object that would otherwise have been returned, and that would have contained a.

If you used

function myFunc() {
  return {
    a:"aaa",
    h:function() { alert this.a; }
  }
}

then it would work!

If you want to use 'private' and 'public' variables then make it like this

function myFunc() {
  var a = "aaa";
  return {
    h:function() { alert a; }
  }
}
Willem Mulder
  • 12,974
  • 3
  • 37
  • 62
5

If you want to use closure, create a as a local variable. This will make a as a private property which outside world will not be able to access directly

function myFunc(){
    var a = "aaa";

    return {
        h: function ()   {
            alert(a);
        }
    }
}

var f = new myFunc();
console.log(f.h(f))

Demo: Fiddle

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • what about this situation where the function is outside ? http://jsbin.com/ofucac/4/edit – Royi Namir Apr 20 '13 at 13:07
  • it will not work because `a` is not available outside `myFunc`, it is accessible via only closure – Arun P Johny Apr 20 '13 at 13:13
  • in that case you need a instance variable as mentioned in the accepted answer, then you can pass `this` to `s` and in `s` you can access `a` via the `param.a` – Arun P Johny Apr 20 '13 at 13:14
2

When you are returning an object from the function you are getting that object instead of the object that was created by the ˋnewˋ keyword. The object where you put the ˋaˋ property doesn't exit any more.

Put the method in the object that is created instead of creating a different object:

function myFunc() {
  this.a = "aaa";

  this.h = function () {
    alert(this.a);
  }
}

Now the object contains the property, so you don't need to use apply to get the right context:

var f = new myFunc();
console.log(f.h())
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

First, keep track of how you're returning and printing items. You're attempting to use both alert and console.log for this job when you should be only using one. In addition, you're attempting to console.log the return value of a function that doesn't return anything. For my example below, I chose to use console.log and kept the function returning nothing. Below, I fixed this first problem:

function myFunc() {
    this.a = "aaa";
    return {h: function () {console.log(this.a);}}
}

var f = new myFunc();
f.h.apply(f);

Now onto the real problem. this.a returns undefined because this is bound to different two different things (first an instance of myFunc, and then f) the two times you use it in your code. You can use console.log(this) to verify this.

To solve this problem, bind a variable (let's call it self) to this so that you can reference it later. In JavaScript, inner functions have access to variables bound in outer functions. (This is called closure.) This allows us to use self in the following way:

function myFunc() {
    var self = this;
    this.a = "aaa";
    return {h: function() {console.log(self.a);}}
}

var f = new myFunc();
// f.h.apply(f); // replaced by next line; see first comment
f.h();

This prints the line aaa to the console.

Community
  • 1
  • 1
interestinglythere
  • 1,230
  • 13
  • 16
  • Thanks. p.s.- like my answer to bangerang , the `apply` in your sample is redundant. cause you're keeping the context. and so-- your code can be changed to `f.h()` - without the `apply` – Royi Namir Apr 20 '13 at 12:29
  • Ooh, didn't see the other answers until after I posted. Fixed! – interestinglythere Apr 20 '13 at 12:33
0

You are losing scope with the closure, try this:

function myFunc()
{
    this.a = "aaa";
    that = this;
    return {
        h: function ()
        {
                   alert(that.a);
        }
    }
}



var f = new myFunc();
console.log(f.h.apply(f)) 
bangerang
  • 473
  • 1
  • 6
  • 15