2
function Foo(x) {
    this.bar = function() { return x; /* but not always */ }
}

Foo.prototype.baz = function() {
    return this.bar(); // Case 2 - should return x
};

var f = new Foo(3);
f.bar(); // Case 1 - should return undefined 
f.baz(); // should return x which is 3 in this case

So, bar is an instance method of f which is an instance of Foo.
On the other hand, baz is a prototype method of Foo.

What I would like is this:

bar should return x (the argument passed into the constructor function), but only if it is called from within a prototype method (a method of Foo.prototype). So, bar should check whether the current execution context is a Foo.prototype function, and only then bar should return x.

In Case 1, the current execution context is Global code, so the return value of the bar call should be undefined. (By this, I mean: I want it to return undefined in this case.)

However in this case 2, the current execution context is Function code of a Foo.prototype function, so the return value of the bar call should be x.

Can this be done?


Update: A real-world example:

function Foo(x) {
    this.getX = function() { return x; /* but not always */ }
}

Foo.prototype.sqr = function() {
    var x = this.getX(); // should return 3 (Case 2)
    return x * x;
};

var f = new Foo(3);
f.getX(); // should return undefined (Case 1)
f.sqr(); // should return 9

Case 1: getX is called "directly" -> return undefined
Case 2: getX is called from within a prototype method -> return x

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • i guess you could use arguments.callee.caller, but it is really deprecated and shouldn't be used – Martin Jespersen Mar 03 '11 at 14:48
  • Why do you need it? I can't find the usefulness of it... – Martin Jespersen Mar 03 '11 at 14:56
  • @Martin Look at the update in my question. I am passing a number into `Foo`. I want that number to be accessible to prototype methods, but I don't want that number to be retrievable directly without using a prototype method. – Šime Vidas Mar 03 '11 at 15:02
  • @Martin The expression `arguments.callee.caller == Foo.prototype.baz` (when placed inside `bar`) indeed does evaluate to false in the first case and true in the second case, which makes it a valid solution. – Šime Vidas Mar 03 '11 at 15:04
  • I know, but it is deprecated and thus not really ideal, read more here: http://stackoverflow.com/questions/103598/why-was-the-arguments-callee-caller-property-deprecated-in-javascript - in ECMAScript 5 Strict Mode they won't exist at all. – Martin Jespersen Mar 03 '11 at 15:10
  • @Martin I have tried to answer my question below. I use `getX.caller` instead of `arguments.callee.caller`. Would that be OK? – Šime Vidas Mar 04 '11 at 01:34
  • I wouldn't do that since that is not even part of the ecma standard. if you wish to go that way, be sure to test it through all borwsers... i think you'll find it won't work in a few of them :) – Martin Jespersen Mar 04 '11 at 08:33
  • @Martin `caller` seems to be supported in all browsers (even IE6). See here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/caller – Šime Vidas Mar 04 '11 at 11:33
  • @Sime: In that case, use it :) It all comes down to what you want and need. I am only here to offer advise :) – Martin Jespersen Mar 04 '11 at 12:04

2 Answers2

0

In Case 1, the current execution context is Global code, so the return value of the bar call should be undefined.

you're using a closure, that is why the method getX has acces to the variable x. It's javascript behaving as intended.

Stephen
  • 18,597
  • 4
  • 32
  • 33
  • Method getX having access to the variable x is not the point here. I want getX to return undefined if its caller is not a prototype method. – Šime Vidas Mar 04 '11 at 01:20
0

So this is my own solution:

function Foo(x) {
    function getX() { 
        return getX.caller === Foo.prototype.sqr ? x : void 0;
    }
    this.getX = getX;
}

Foo.prototype.sqr = function() {
    var x = this.getX();
    return x * x;
};

var f = new Foo(3);
console.log( f.getX() ); // logs undefined 
console.log( f.sqr() ); // logs 9

As you can see, I had to define getX as a local function of the Foo constructor (and then assign this function to the instance via this.getX = getX;. Inside getX, I explicitly check whether getX.caller is Foo.prototype.sqr.

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385