简体   繁体   中英

how to access a variable from outside a function/instance

I have this very simple JavaScript code that should return a Fullname using parameters firstname and lastname All works fine when I alert out the fullname within the function. But I'm struggling how to make the fullname variable accessible from outside the function/instance?

here's my code:

var getName = function () {

    this.name = function (firstname, lastname, success) {
        var fullName = firstname + " " + lastname;
        success(fullName);
    };

};


var test = new getName();

test.name("John", "Smith", function (output) {
    var fullname = output;
    alert(fullname); //this works fine
    return fullname; // I need this variable to be accessed from outside this function
});

var myName = fullname; //I need to create the variable here
alert(myName); //this does not work

Here's Fiddle

Thank you very much for your help.

Edit: I'm building an iPad app where I'm using cordova and javascript plugins. One of the plugin gives me access to the file inside the device. Now, I need to be able to get the path and use it outside the callback so that I can use anywhere in the scope:

Here's the plugin code:

var FileManager = function(){

this.get_path = function(todir,tofilename, success){
        fail = (typeof fail == 'undefined')? Log('FileManager','read file fail'): fail;
        this.load_file(
            todir,
            tofilename,
            function(fileEntry){

                var sPath = fileEntry.toURL();
                success(sPath);
            },
            Log('fail')
        );

    }


    this.load_file = function(dir, file, success, fail, dont_repeat){
        if(!dir || dir =='')
        {
            Log('error','msg')('No file should be created, without a folder, to prevent a mess');
            fail();
            return;
        }
        fail = (typeof fail == 'undefined')? Log('FileManager','load file fail'): fail;
        var full_file_path = dir+'/'+file;
        var object = this;
        // get fileSystem
        fileSystemSingleton.load(
            function(fs){
                var dont_repeat_inner = dont_repeat;
                // get file handler
                console.log(fs.root);
                fs.root.getFile(
                    full_file_path,
                    {create: true, exclusive: false},
                    success,

                    function(error){

                        if(dont_repeat == true){
                            Log('FileManager','error')('recurring error, gettingout of here!');
                            return;
                        }
                        // if target folder does not exist, create it
                        if(error.code == 3){
                            Log('FileManager','msg')('folder does not exist, creating it');
                            var a = new DirManager();
                            a.create_r(
                                dir,
                                function(){
                                    Log('FileManager','mesg')('trying to create the file again: '+file);
                                    object.load_file(dir,file,success,fail,true);
                                },
                                fail
                            );
                            return;
                        }
                        fail(error);
                    }
                );
            }
        );
    };
}

and here's how I use it:

    var b = new FileManager(); // Initialize a File manager

    b.get_path('Documents','data.json',function(path){
        myPath = path;
        console.log(myPath); //this gives me the path of the file in the console, which works fine
        return myPath; //I return the path to be accessed outside
    });

    var filePath = myPath; //here I need to access the path variable
    console.log(filePath)// here, the path is undefined and it does not work

    //Since I'm using angular services to retrieve the data from json, I'd like to pass the filePath
  //this is a fraction of code for retrieving data:
  return $resource('data.json',{}, {'query': {method: 'GET', isArray: false}});

  //passing the value does not work
  return $resource(filePath,{}, {'query': {method: 'GET', isArray: false}});

  //even wrapping resource around instance does not work, it breaks the whole app
  b.get_path('Documents','data.json',function(path){
        myPath = path;
        console.log(myPath); //this gives me the path of the file in the console, which works fine
        return $resource(myPath,{}, {'query': {method: 'GET', isArray: false}});
    });

Factory services:

'use strict';
angular
    .module ('myApp')
    .factory('getMeData', function ($resource) {
        var b = new FileManager(); // Initialize a File manager
        b.get_path('Documents','data.json',function(path){
            myPath = path;
            return myPath;
        });

        //below doesn't work when passing path (it is undefined)
        return $resource(myPath,{}, {'query': {method: 'GET', isArray: false}});

        //when wrapping it around, the app crashes
        b.get_path('Documents','data.json',function(path){
            myPath = path;
            return $resource(myPath,{}, {'query': {method: 'GET', isArray: false}});
        });

        //none of the solution above work

    });

If you have the name function return the result of success then you can use the return from the method.

Ie

var getName = function () {
    this.name = function (firstname, lastname, success) {
        var fullName = firstname + " " + lastname;
        return success(fullName);
    };

};


var test = new getName();

var myName = test.name("John", "Smith", function (output) {
    var fullname = output;
    alert(fullname); //this works fine
    return fullname; // I need this variable to be accessed from outside this function
});
alert(myName);

Define fullname outside the callback.

var getName = function () {

    this.name = function (firstname, lastname, success) {
        var fullName = firstname + " " + lastname;
        success(fullName);
    };

};


var test = new getName();
var fullname;
test.name("John", "Smith", function (output) {
    fullname = output;
    alert(fullname); //this works fine
    return fullname; // I need this variable to be accessed from outside this function
});

alert(fullname);

Hope it helps. Fiddle

If async required:

Assuming the actual source of the code is an async one, now confirmed from your comment, you should simply process the result within the callback. The value is simply not available outside of the callback as the result arrives later.

The answers by @Jim and @bestmike007 will not work with an async operation as it returns a value from inside a callback which may occur long after the function is run. (note: @bestmike007 does have an improved answer linked in a comment).

eg Look at what happens here: http://fiddle.jshell.net/y1m36w9p/1/ or here http://jsfiddle.net/TrueBlueAussie/opczeuqw/1/

The only way to work with async code is in an async manner. That means you can only handle the result inside the callback:

// Get the fullname asyc and process the result
test.name("John", "Smith", function (fullname) {
    alert(fullname); // you can only work with the result in here
});

An alternative is to return a jQuery promise from getName.name() , but the end result will still be a callback to do the work, but this time it would look like this:

test.name("John", "Smith").done(function(fullname){
    alert(fullname); // you can only work with the result in here
});

but this is more code and complication for no extra benefit at this time.

For your specific updated example code:

I am not familiar enough with Angular to confirm this, and would need to see how getMeData is called, but you should use another callback as a parameter to the getMeData function you register:

'use strict';
angular
    .module ('myApp')
    .factory('getMeData', function ($resource, callback) {
        var b = new FileManager(); // Initialize a File manager
        b.get_path('Documents','data.json',function(path){
            callback($resource(path,{}, {'query': {method: 'GET', isArray: false}}));
        });
    });

If async not required (obsolete option)

If (as a previous contradictory comment below said) this was not mean to to be async, then do not use callbacks at all, just simple functions/methods returning values: http://fiddle.jshell.net/y1m36w9p/2/

eg

var getName = function () {
    this.name = function (firstname, lastname) {
        return firstname + " " + lastname;
    };
};

// Create a instance of the getName class
var test = new getName();

// Get the fullname asyc and process the result
var fullname = test.name("John", "Smith");

// Do what you like with the value returned from the function
alert(fullname); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM