Не удается получить доступ к переменной с помощью call в Javascript

#javascript

#javascript

Вопрос:

Я изучаю Javascript и учусь, как использовать call . Я создал этот скрипт, и я не знаю, почему у меня не может быть доступа к этой переменной 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
});  

Итак, как я могу получить значение времени внутри newTest функции?

Комментарии:

1. Я немного сбит с толку. В вашей newTest функции вы нажимаете execute на массив, но он не вызывается. Также альтернативным вариантом является использование execute.bind(this) вместо function(){ execute.call(this) }

2. Анонимная функция this ссылается на window . Попробуйте выполнить function() { console.log(this.time); }.bind(this)

3. @AndrewLi Нет. this указывает на временную функцию, test поскольку OP использует .call(this) внутри test

Ответ №1:

Проблема в newTest функции

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

Здесь this указано на test , а не Runner . Вам нужно будет сохранить контекст в переменной, а затем установить его в 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

Как указано, вы даже можете использовать .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()  

Комментарии:

1. Спасибо! Теперь все работает нормально!

2. Просто указатель, (MyObject|| (MyObject= {}) должен быть (MyObject || {})

Ответ №2:

Когда вы объявляете свою функцию Runner, вы фактически объявляете функцию, которая не принимает аргументов, которая затем сама объявляет функцию с именем Runner, которая принимает один аргумент.

Ответ №3:

На самом деле в этом фрагменте кода :

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

это будет ссылаться на тестовую переменную (согласно шаблону вызова конструктора)
Итак, чтобы передать правильную переменную, кэшируйте значение this в другой переменной, а затем передайте это функции.