0

I'm trying to avoid using global variable when using functions within objects. I want to invoke a function inside other function and use a variable from the first function's scope. For example:

var showForecast = {
  'init': function () {
    this.getData();
  },
  'buildView': function(){
    var code = "Hey, you're from " + this.data.city;
    $('body').append(code);
  },
  'getData': function () {
    $.getJSON('http://ipinfo.io/', function (data) {
      console.log(data);
      showForecast.buildView();
    })
  }
}

Clearly it's not working. I want to use data inside buildView without making data a global variable. I thought using this would be the right course of action because I'm calling buildView from a function where data is defined. How can this be achieved? Thanks.

2
  • @Oriol — buildView is called from the callback, so being asynchronous doesn't matter. Commented Feb 12, 2016 at 19:08
  • OK, I misunderstood the code. Commented Feb 12, 2016 at 19:11

4 Answers 4

2

You can pass the information along:

var showForecast = {
'init': function () {
    this.getData();
},
'buildView': function(data){
    var code = 'Hey, you\'re from ' + data.city;
    $('body').append(code);
},
'getData': function () {
    $.getJSON('http://ipinfo.io/', function (data) {
        console.log(data);
        showForecast.buildView(data);
    })
}

}
Sign up to request clarification or add additional context in comments.

Comments

1

There is no way to access the data variable itself. That is locally scoped to the anonymous function you pass to getJSON (and getJSON passes it as an argument, which is beyond your control).

You have to copy the value somewhere.

In your particular example, there are no scopes shared between getData and buildView other than the global scope. So if you want to pass the value through scopes, then a global is your own (terrible) option.

You can simply pass it as an argument:

showForecast.buildView(data);

Or you can store it as a property:

showForecast.myData = data;

Comments

1

I like Vinny's answer.

One round-bout way is to make a module out of it:

var showForecast = function(){
    var data;
    var init = function () {
        this.getData();
    };
    var buildView = function(){
        var code = 'Hey, you\'re from ' + this.data.city;
        $('body').append(code);
    };
    var getData = function () {
        $.getJSON('http://ipinfo.io/', function (data) {
            console.log(data);
            this.data = data;
            showForecast.buildView();
        })
    };
    return {
        'init': init,
        'buildView': buildView,
        'getData': getData
    };
}();

This way the scope of var data is limited to the function. It's like a private variable.

Comments

0

As you are trying to avoid global, you should consider using namespaces. There is no such thing called namespace in Javascript. But you can define yourself using small utility method mentioned here.

http://www.zachleat.com/web/namespacing-outside-of-the-yahoo-namespace/

A utility method which helps creating custom namespaces.

jQuery.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=window;
        for (j=0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }
    return o;
};

Define name space

jQuery.namespace( 'jQuery.showForecast' );    

Define methods using revealing module pattern

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript

 jQuery.showForecast = (function() {

  var data;

  var init = function() { 
    getData();
  }

  var buildView = function() {
    var code = "Hey, you're from " + data.city;
    $('body').append(code);
  }

  var getData = function() {        
    $.getJSON('http://ipinfo.io/', function(_data) {
      console.log(data);
      data = _data;
      buildView();
    })

  }

  return {
    init: init
  };

})(); // Execute it immediately

Usage:

You can access only init method as it is exposed to outside.

jQuery.showForecast.init()

Define another namespace

jQuery.namespace( 'jQuery.showForecast.extended' );

jQuery.showForecast.extended = {
// Define some more

};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.