0

Say I have the following object definition:

var car = function (engine) { 
    this.engine = engine;

    this.calculateSpeed = function () {
        return engine.power * 20;
    };
};

the engine object in the calculateSpeed() function refers to the engine object passed in via the constructor and not the car's public engine member(which is the one I want).

If I wanted to change the engine of the car after creating the car object I want the calcuateSpeed() function to reference the new engine.

The Inner function cannot access outer functions variable question is similar to mine. But does not quite cover my use case as the OP is using a local variable and has no constructor.

If you could also explain why this won't work, that would also help a lot:

var car = function (engineInit) { 
    this.engine = engineInit;

    this.calculateSpeed = function () {
        return engine.power * 20;
    };
};

I know for this simple example I could use this.calculateSpeed = engine.power * 20; but for my real use case, I need a function.

5
  • 1
    what problem are you having using this.engine.power? Commented Jun 16, 2018 at 23:02
  • As I mentioned in my question, this.engine.power is scoped to the calculateSpeed function and not to the car object. Commented Jun 16, 2018 at 23:05
  • Possible duplicate of What underlies this JavaScript idiom: var self = this? Commented Jun 16, 2018 at 23:06
  • @StormMuller not sure a I agree. Did you check my answer? Commented Jun 16, 2018 at 23:22
  • @user3210641 yea, you're right. Seemed I was experiencing a closure issue. I accepted Josh's as it answered the question I posted. As well as helped me avoid my closure issue. Commented Jun 16, 2018 at 23:31

3 Answers 3

2

You can actually use this.engine.power.

// Define Car constructor
const Car = function (engineInit) { 
    this.engine = engineInit;

    this.calculateSpeed = function () {
        return this.engine.power * 20;
    };
};

// Create new car instance
const carInstance = new Car({ power: 100 });

// Log the result of calculateSpeed function
console.log(carInstance.calculateSpeed());

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

3 Comments

@Musa why did you edit the answer? Or more accurately why did you add unrelated code?
To show that in the calculation the engine being used is not the one passed in the constructor. If the edit is wrong you can always undo it.
How would the this keyword behave if calculateSpeed had a local engine variable?
1

If you want the internal engine to be separate from the engine property visible on the outside of the instantiated Car, you might consider simply having another locally scoped variable, separate from the initial engine parameter, and reassigning it as necessary:

var Car = function(initialEngine) {
  this.engine = initialEngine;
  let engine = initialEngine;
  this.calculateSpeed = function() {
    return engine.power * 20;
  };
  this.changeEngine = function(newEngine) {
    engine = newEngine;
  }
};

var car = new Car({ power: 20 });
console.log(car.calculateSpeed());
car.changeEngine({ power: 40 });
console.log(car.calculateSpeed());

2 Comments

now add console.log(car.engine.power); to the last line. Car's engine hasn't changed.
I thought you said you wanted them to be different for some reason? refers to the engine object passed in via the constructor and not the car's public engine member(which is the one I want). If you actually do want to assign to the property of the instantiated object, just assign to it as normal, this.engine = newEngine
0

This question is a duplicate of many other questions on stackoverflow, but here is something to get you started anyway.

By capturing this in another variable:

var car = function(engineInit) { 
  this.engine = engineInit;
  var self = this;
  this.calculateSpeed = function () {
    return self.engine.power * 20;
  };
};

By using bind:

var car = function(engineInit) { 
  this.engine = engineInit;
  this.calculateSpeed = function () {
    return this.engine.power * 20;
  }.bind(this);
};

By using a function's prototype:

function Car(engine) { 
  this.engine = engine;
}

Car.prototype.calculateSpeed = function() {
  return this.engine.power * 20;
};

var engine = new Engine();
var car = new Car(engine);
var speed = car.calculateSpeed();

2 Comments

Cool thanks Josh, could you please add the duplicates to my question, so that other who come here can see them too? Also I like the var self = this solution. Bind is changing scope of the local function which seems like a code smell and the prototype solution means that my object lives in 2 places which is also not ideal. Thanks!
Prototype is actually your best pick as you can only create the calculateSpeed function once. In all the other instances (including the one mentioned in my answer) you create new function every time you create a new Car instance.

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.