Почему setInterval () с объявлением функции в качестве аргумента работает иначе, чем с анонимной функцией? - PullRequest
1 голос
/ 24 мая 2019

Я не понимаю, почему использование имени функции в setInterval не работает правильно, но передача анонимной функции работает правильно.

пример не работает (это запись в консоль NaN и перед первым вызовом this.counter ++ этовозвращает undefined, так как не может найти переменную?)

export class MyClassName {
 counter = 0;

 startInterval(){
   setInterval(this.myFunc , 1000)
 }

 myFunc(){
   this.counter++;
   console.log(this.counter)
 }
}

, но с измененным startInterval, как показано ниже, он работает правильно

startInterval(){
  setInterval(() => this.myFunc() , 1000)
}

, а в html мы имеем

<button (click)="startInterval()">Start</button>

Ответы [ 3 ]

2 голосов
/ 24 мая 2019

В первом примере вы передаете ссылку на функцию без ее запуска.Когда он запускается, он запускается в глобальном контексте, где this не определено, или this относится к объекту Window.Вы можете убедиться, что он действительно ссылается на объект Window, зарегистрировав значение this.constructor.name:

class MyClassName {
 counter = 0;

 // You are passing in a function name but not running it yet.
 // It will be run in a global context by setInterval.
 startInterval(){
   setInterval(this.myFunc, 1000)
 }

 myFunc(){
   // When run in global context, this no longer refers to our instance.
   console.log(this.constructor.name);
   this.counter++;
   console.log(this.counter)
 }
}

const mc = new MyClassName();

mc.startInterval();

Во втором примере функции стрелок используют this того, где они объявлены, а не того места, где они выполняются.Таким образом, this класса представлен ниже, даже если функция стрелки будет выполняться в глобальном контексте.

class MyClassName {
 counter = 0;

 // Arrow functions use the `this` of where they are declared, not where they are run.
 // So the `this` of the class is captured below, even though the arrow function
 // will run in the global context.
 startInterval(){
   setInterval(() => this.myFunc(), 1000);
 }

 myFunc(){
   console.log(this.constructor.name);
   this.counter++;
   console.log(this.counter)
 }
}

const mc = new MyClassName();

mc.startInterval();

Вы можете найти довольно хорошее резюме того, как именно это работает конкретно с setInterval в документах MDN для функций стрелок .

1 голос
/ 24 мая 2019

Расхождение связано с ключевым словом this . В javascript функции anonymous / arrow не создают this для ссылки на вызывающую функцию. в то время как обычная функция, объявленная с ключевым словом function , будет захватывать вызывающую функцию в this .

Следовательно, в вашем первом примере startInterval () вызывается элементом button, у которого нет переменной counter. А во втором примере ключевое слово this относится к внешней области видимости this , которая является объектом окна. Я предполагаю, что MyClassName создается под объектом окна, поэтому счетчик существует.

Дополнительное чтение: https://www.codementor.io/dariogarciamoya/understanding-this-in-javascript-with-arrow-functions-gcpjwfyuc

0 голосов
/ 24 мая 2019

Это потому, что ваш this вызывает функцию и, следовательно, myFunc не определен. Вы можете узнать о this контексте с помощью быстрого поиска. Некоторые примеры: 1 , 2 .


Вы можете проверить это, войдя в систему this.myFunc. То же самое произойдет с this.counter, если его когда-либо вызовут.

let counter = 0;

const startInterval = () => {
  // undefined, and hence it does not exist.
  console.log(this.myFunc);
  setInterval(this.myFunc, 1000);
};

startInterval();

const myFunc = () => {
  this.counter++;
  console.log(this.counter);
};

Вы можете просто исправить свой код, переупорядочив функции и удалив this.

let counter = 0;

const myFunc = () => {
  counter++;  // Remove this from here as well.
  console.log(counter);
};

const startInterval = () => {
  // Defined, and hence it works.
  setInterval(myFunc, 1000);
};

startInterval();
...