JavaScript — Карта объектов применяет функцию только к последнему объекту (возможная проблема с подъемом)

#javascript #javascript-objects

#javascript #javascript-объекты

Вопрос:

Я создал WebPage функцию, которая должна действовать как класс.

У меня есть карта url ключей и WebPage значений объектов, и я хочу вызвать метод для каждого объекта. Вызываемый метод startMonitoring должен устанавливать interval значение переменной, ограниченной для каждого объекта.

Однако интервал устанавливается только для последнего объекта, и каждый другой объект получит тот же результат при последующей печати.

Вот мой код:

 export const startMonitoring = (websitesMap) => {
    websitesMap.forEach((website) => {
        website.startMonitoring();
    });
};
export function WebPage(url, checkTime) {
    // other variables
    this.scheduledTask;
    ...
    WebPage.prototype.startMonitoring = () => {
        this.scheduledTask = setInterval(async () => {
            // asynchronous work
        }, checkTime * 1000);
    };
}
  

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

1. => функции не задают this способ function , которым работают функции.

2. Каждый раз, когда вы создаете новый экземпляр WebPage , вы также переназначаете WebPage.prototype.startMonitoring функцию. Я сомневаюсь, что это то, чего вы хотите. Почему вы не используете обычный класс?

Ответ №1:

Это происходит потому, что вы устанавливаете прототип каждый раз, когда создаете новый объект. Таким образом, все экземпляры будут обращаться к последнему, который вы определяете.

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

 export const startMonitoring = (websitesMap) => {
    websitesMap.forEach((website) => {
        website.startMonitoring();
    });
};
export function WebPage(url, checkTime) {
    // other variables
    this.scheduledTask;
    this.checkTime = checkTime;
    ...
}
WebPage.prototype.startMonitoring = function() {
    this.scheduledTask = setInterval(async function() {
        // asynchronous work
    }, this.checkTime * 1000);
};
  

Ответ №2:

Как сказал Pointy, используя прототип, это сработало бы:

 const startMonitoring = (websitesMap) => {
  websitesMap.forEach((website) => {
      website.startMonitoring();
  });
};

function WebPage(url, checkTime) {
  // other variables
  this.scheduledTask;
  this.url = url;
  
  WebPage.prototype.startMonitoring = function() {
      this.scheduledTask = setInterval(async () => {
          console.log('hello', this.url);
      }, checkTime * 1000);
  };
}

const websites = [new WebPage('#', 1), new WebPage('#test', 1)]
startMonitoring(websites);  

Кроме того, изменение функции прототипа также должно работать:

 const startMonitoring = (websitesMap) => {
  websitesMap.forEach((website) => {
      website.startMonitoring();
  });
};

function WebPage(url, checkTime) {
  // other variables
  this.scheduledTask;
  this.url = url;
  
  this.startMonitoring = () => {
      this.scheduledTask = setInterval(async () => {
          console.log('hello', this.url);
      }, checkTime * 1000);
  };
}

const websites = [new WebPage('#', 1), new WebPage('#test', 1)]
startMonitoring(websites);  

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

1. Имейте в виду, что когда вы создаете методы в «классе», подобном этому, у вас будут повторяющиеся экземпляры метода в памяти, тогда как если бы вы использовали методологию прототипа, у вас был бы только один. Пример: jsfiddle.net/Lbqyu096

2. А, понятно. Спасибо.

3. Строка прототипа действительно должна быть вне функции, иначе она будет повторно запускаться для каждого вызова.

4. Хм, тогда мы теряем доступ к переменным экземпляра. Возможно, это должна быть не прототипированная функция?

5. Чтобы иметь доступ к this , это должна быть функция-прототип, а не функция со стрелкой