Royi Namir
Royi Namir

Reputation: 148524

Can't change context in Javascript ?

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 ?

Upvotes: 1

Views: 110

Answers (5)

Willem Mulder
Willem Mulder

Reputation: 13994

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; }
  }
}

Upvotes: 6

interestinglythere
interestinglythere

Reputation: 1253

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.

Upvotes: 1

Guffa
Guffa

Reputation: 700212

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())

Upvotes: 2

Arun P Johny
Arun P Johny

Reputation: 388316

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

Upvotes: 5

bangerang
bangerang

Reputation: 483

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)) 

Upvotes: 0

Related Questions