0

I thought I understood how call worked in javascript, but apparently not.

function bear(){
    var a = 1
    pig.call(this) 
}

function pig(){
    alert(a) //throws an error, 'a is not defined'
}

bear()

http://codepen.io/anon/pen/jEYGOv

Why doesn't this work? How could I make it work (without passing a as a variable)

A F
  • 7,424
  • 8
  • 40
  • 52
  • 1
    Because *this* is a parameter of an execution context, it does not represent the context (no matter how often people refer to it as "context"). You can't reference an execution context, the language specification forbids it. – RobG Feb 11 '15 at 03:44
  • @RobG Thanks - that clarifies a lot. Its also quite a bummer. – A F Feb 11 '15 at 03:48

3 Answers3

1

You can't do that.

function bear(){
  pig.call(this);
}

function pig(){
  this.a = 5; //same as window.a = 5 unless used as a constructor;
}
bear(); //window.a == 5;
a = new bear(); //this keyword is now referring to variable object a so a.a = 5;

Also any parameters after the first for .call(this) would be the arguments of the function that you're calling call() on

Edwin Reynoso
  • 1,511
  • 9
  • 18
  • 1
    Note that in strict mode, *this* will be undefined so *this.a* will throw an error. – RobG Feb 11 '15 at 03:48
1

Why doesn't this work? How could I make it work (without passing a as a variable)

What you did here is sharing the context with Function.prototype.call. Sharing the context does not share the scope variables. Scope variables aren't accessible from outside of the scope and the pig() runs in a different scope than the bear().

What you can do is

a.) sending the common variable in the arguments:

// recommended

function bear(){
    var a = 1;
    pig(a); 
}

function pig(a){
    alert(a);
}

bear();

b.) defining an object to be the common context:

// not recommended
// hard to follow where the context is coming from

function bear(){
    this.a = 1;
    pig.call(this); 
}

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

var o = {};
bear.call(o);

or

// recommended

var o = {
    a: undefined,
    bear: function (){
        this.a = 1;
        this.pig(); 
    },
    pig: function pig(){
        alert(this.a);
    }
};

o.bear();

c.) defining a class

// not recommended
// you are defining the methods (bear and pig) by each instantiation

var My = function (){
    this.bear = function (){
        this.a = 1;
        this.pig(); 
    };
    this.pig = function pig(){
        alert(this.a);
    };
};

var o = new My();
o.bear();

or

// recommended

var My = function (){};
My.prototype = {
    constructor: My,
    a: undefined,
    bear: function (){
        this.a = 1;
        this.pig(); 
    },
    pig: function pig(){
        alert(this.a);
    }
};

var o = new My();
o.bear();

d.) defining a common variable in an upper scope

// not recommended
// (unless we are talking about a commonjs module which has its own scope)
// don't pollute the global scope with local variables

var a;

function bear(){
    a = 1;
    pig(a); 
}

function pig(a){
    alert(a);
}

bear();

or with closure

// recommended

(function (){
    var a;

    function bear(){
        a = 1;
        pig(a); 
    }

    function pig(a){
        alert(a);
    }

    bear();
})();
inf3rno
  • 24,976
  • 11
  • 115
  • 197
0

You need to take a look at the scope of variables:

<script type="text/javascript">
var a;

function bear(){
    a = 1
    pig.call(this) 
}

function pig(){
    alert(a);
}

bear();
</script>
Community
  • 1
  • 1
Samuel Cook
  • 16,620
  • 7
  • 50
  • 62
  • 1
    yes, but this way it wouldn't be needed to do the `call()` part because it would set the `a` variable globally and alert it anyway – rsz Feb 11 '15 at 03:36