AmorphousCrystal
AmorphousCrystal

Reputation: 64

JavaScript accessing variables declared in calling function

It's hard to explain my question, so I'm posting some code.

function caller(func) {
    function printMessage(message) {
        console.log(message);
    }

    func();
}

function callee() {
    printMessage('hello world');
}

caller(callee);

I want to access printMessage from callee, but as it currently stands, this throws a ReferenceError. I'd like to avoid declaring printMessage globally, if possible.

Upvotes: 0

Views: 1486

Answers (4)

AmorphousCrystal
AmorphousCrystal

Reputation: 64

eval seems to achieve this rather elegantly.

function caller(func) {
    function printMessage(message) {
        console.log(message);
    }

    eval('(' + func.toString() + ')();');
}

function callee() {
    printMessage('hello world');
}

caller(callee);

Upvotes: 0

Ivan Sivak
Ivan Sivak

Reputation: 7498

Basically, you can't. The nested printMessage is limited to caller scope only.

You can access the caller constructor function by its calee.caller prototype but it's "locked" under caller's scope only..

Just for info:

function caller(func) {
    function printMessage(message) {
        console.log(message);
    }

    func();
}

function callee() {
    //you can access the caller's constructor from prototype..
    var callerFunc = arguments.callee.caller.prototype;
    console.log(callerFunc);
    //you can get the actual code
    var code = arguments.callee.caller.toString();
    console.log(code);

    //but you can't invoke the nested function which is under
    //caller scope only...will throw ReferenceError
    printMessage('hello world');
}

caller(callee);

jsfiddle: http://jsfiddle.net/ufxnoaL1/

Also, note that arguments.callee will not be supported and should not be used

Warning: The 5th edition of ECMAScript (ES5) forbids use of arguments.callee() in strict mode. Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself.

Upvotes: 0

D-Bennett
D-Bennett

Reputation: 155

One thing you could do would be to have 'caller' call the function passed into it, and print the returned value.

function caller(func) {
  function printMessage(message) {
    console.log(message);
  }
  printMessage(func());
}
function callee() {
  return 'hello world';
}
function callee2() {
  return 'hello world 2';
}
caller(callee);
caller(callee2);

Edit

After reading your comments on question, this may be better suited to an OO approach e.g:

//--- Base 'libary' caller ---//
var caller = function() {

}
//--- Add out printMessage function to our base libary ---//
caller.prototype.printMessage = function(message){
    console.log(message);
}

//--- Users 'libary' callee ---//
var callee = function() {
    caller.call(this);
    //--- Our users libary has a printing function ---//
    this.print = function ( message ) {
        this.printMessage("callee > " + message);
    }
}
callee.prototype = Object.create(caller.prototype); // Set callee's prototype to caller's prototype
callee.prototype.constructor = callee; // Set constructor back to callee

//--- Using the users libary ---//
var userLibary = new callee();
userLibary.print("hello world"); // 'callee > hello world'
//--- The original libary's print method is still accessible ---//
userLibary.printMessage("hello world"); // 'hello world'

Upvotes: 0

Scott Hunter
Scott Hunter

Reputation: 49920

You could pass the function you want to use inside of callee as a parameter to callee; so long as the caller has access, then callee doesn't care where it was defined:

function caller(func) {
    ....
    func(printMessage);
}

function callee( func ) {
    func("hello world");
}

Upvotes: 1

Related Questions