2

I am currently learning OOP in JavaScript. I'm refactoring an app and I have a problem.

I have created a Class "Weather"

 class Weather {

  constructor({longitude, latitude} = {}) {
    this.longitude = longitude;
    this.latitude = latitude;
    this.options = {
      enableHighAccuracy: true,
      timeout: 5000,
      maximumAge: 0
    };
  }

  getLongitude(){
    return this.longitude;
  }

  setLongitude(longitude){
    this.longitude = longitude;
  }

  getLatitude(){
    return this.latitude;
  }

  setLatitude(latitude){
    this.latitude = latitude;
  }

  getLocation() {
      if (Modernizr.geolocation) {
          //if locatin is enabled, show position in button
          navigator.geolocation.getCurrentPosition(this.success, this.fail, this.options);
      } else {
          alert("Sorry, you browser doesn't have geolocation");
      }
  }

   success(position){
    let pos = position.coords;
    console.log('Your actual position is :');
    console.log(`Latitude : ${pos.latitude}`);
    console.log(`Longitude: ${pos.longitude}`);
    console.log(`More or less ${position.coords.accuracy} meters.`);
    this.setLongitude(pos.longitude); // <== Doesn't work
    this.setLatitude(pos.latitude); // <== Doesn't work

  }

  fail(){
    console.log('User refused to give position');
  }
}

Everything works, I can retrieve longitude and latitude like that

let City = new Weather();
City.getLocation(); //will call getLocation and on success, it will console.log the longitude and latitude

My problem is that I can update the value of my object. When I create my object, the constuctor defines a longitude and latitude if they are passed as argument. However, in the success method, I cannot reassign value of the object.

Is there any solution ?

3
  • 3
    You may find its to do with the scope of the this variable, common practice is to put a var self = this; at the top, and use self where you want the class this reference. Commented Sep 19, 2017 at 21:30
  • 1
    You can use setters and getters of class javascript Commented Sep 19, 2017 at 21:32
  • You may also do like success(position){bla bla}.bind(this); Commented Sep 19, 2017 at 21:39

4 Answers 4

2

You've lost the context because the success method is passed as a reference. So the value of this when it is called does not refer to the Weather instance. You can use Function.prototype.bind method to fix this:

class Weather {
  ...

  getLocation() {
    if (Modernizr.geolocation) {
      //if locatin is enabled, show position in button
      navigator.geolocation.getCurrentPosition(
        this.success.bind(this),
        this.fail,
        this.options
      );
    } else {
      alert("Sorry, you browser doesn't have geolocation");
    }
  }

  ...
}

Alternatively, you can bind the method in the constructor, so that bind is only called once when the object is instantiated.

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

Comments

0

You can use getters and setters of class javascript.

class Weather {
   constructor({longitude, latitude} = {}) { 
     this.longitude = longitude;
     this.latitude = latitude;
     ...
   }

   get Latitude(){return this.latitude};
   set Latitude(args){this.latitude=args};
   ...
}

Comments

0

First and foremost: Whilst it is still possible to mimic OOP in JavaScript, you should avoid this approach and instead opt for Functional Programming.

To answer your question: When you are invoking success(), as it happens on every function in JS, the context changes and this will be referring to wherever you invoke the code.

To solve this issue you can either use bind(this) or change success to a method instead of a function. Here is how it can be done:

successs: function(position){
    let pos = position.coords;
    console.log('Your actual position is :');
    console.log(`Latitude : ${pos.latitude}`);
    console.log(`Longitude: ${pos.longitude}`);
    console.log(`More or less ${position.coords.accuracy} meters.`);
    this.setLongitude(pos.longitude); // This will work now because this
    this.setLatitude(pos.latitude); // will be referring to the Weather object
}

For further information on how this works in JS please have a look at this explanation: http://blog.andrewray.me/react-es6-autobinding-and-createclass/

Comments

0

As Chris Walks say you are having troubles with the "this" value inside succes s function

Ther are several ways to solve it, the problem is when navigator.geolocation.getCurrentPosition calls success, it sets a different "this" value that you expect on the function

One could be

var me = this;
navigator.geolocation.getCurrentPosition(function(position) {
    me.success(position)
}, this.fail, this.options)

You will have the same proble with this.fail

Another way is

navigator.geolocation.getCurrentPosition(this.success.bind(this), this.fail.bind(this), this.options)

You can learn more from here

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Edited: As sugested first solution is wrong, a pointer to this is need

1 Comment

In that first example you'd still lose the this unless you use a var me = this;. You could use an arrow function for the wrapper instead to avoid that problem.

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.