Tiago Castro
Tiago Castro

Reputation: 7

Can't have access to a variable using call in Javascript

I'm studying Javascript and learning how to use call. I created this script and I don't know why I can't have access to this variable Time.

var MyObject;
(function(MyObject) {
  var Runner = (function() {
    function Runner(time) {
      this.time = time;
    }
    var myFunctionArray = [];
    Runner.prototype.execute = function() {
      myFunctionArray[0]();
    }

    Runner.prototype.newTest = function(index, execute) {
      var test = function() {
        return execute.call(this);
      }
      myFunctionArray.push(test);
    }
    return Runner;
  })();
  MyObject.Runner = Runner;
})(MyObject || (MyObject = {});

var myNewObj = new MyObject.Runner(1000); myNewObj.newTest('1', function() {
  console.log(this.time) //output: undefined
});

So how can I get time value inside newTest function?

Upvotes: 0

Views: 40

Answers (3)

Rajesh
Rajesh

Reputation: 24925

Issue is in newTest function

Runner.prototype.newTest = function(index, execute) {
  var test = function() {
    return execute.call(this);
  }
  myFunctionArray.push(test);
}

Here this is pointing to test and not Runner. You will have to save context in a variable and then set it in call.

Runner.prototype.newTest = function(index, execute) {
  var self = this;
  var test = function() {
    return execute.call(self);
  }
  myFunctionArray.push(test);
}

.call + self

var MyObject;
(function(MyObject) {
  var Runner = (function() {
    function Runner(time) {
      this.time = time;
    }
    var myFunctionArray = [];
    Runner.prototype.execute = function() {
      myFunctionArray[0]();
    }

    Runner.prototype.newTest = function(index, execute) {
      var self = this;
      var test = function() {
        return execute.call(self);
      }
      myFunctionArray.push(test);
    }
    return Runner;
  })();
  MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));

var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
  console.log(this, this.time) //output: undefined
});
myNewObj.execute()

.bind

As commented, you can even use .bind

var MyObject;
(function(MyObject) {
  var Runner = (function() {
    function Runner(time) {
      this.time = time;
    }
    var myFunctionArray = [];
    Runner.prototype.execute = function() {
      myFunctionArray[0]();
    }

    Runner.prototype.newTest = function(index, execute) {
      myFunctionArray.push(execute.bind(this));
    }
    return Runner;
  })();
  MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));

var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
  console.log(this, this.time) //output: undefined
});
myNewObj.execute()

Upvotes: 2

Piyush Sharma
Piyush Sharma

Reputation: 113

Actually In this code snippet :

Runner.prototype.newTest = function(index, execute) {
      var test = function() {
         return execute.call(this);
      }
      myFunctionArray.push(test);
   }

this will reference to test variable (as per constructor invocation pattern) So, to pass right variable cache the value of this in another variable and then pass that to function.

Upvotes: 0

Chris Cousins
Chris Cousins

Reputation: 1912

When you declare your Runner function, you've actually declared a function that takes no arguments that then itself declares a function called Runner that takes one argument.

Upvotes: 0

Related Questions