Предполагаемое использование case `this` в анонимной функции? - PullRequest
2 голосов
/ 16 апреля 2020

Вопрос

Я только начал изучать JS / ES7 сегодня и хотел бы узнать, правильно ли я понял this.

На основе двух фрагменты кода ниже, я полагаю, цель this в том, чтобы можно было выбрать, хотите ли вы наследовать переменные от родительской функции?

Если это правильно, может ли быть случай использования le git использования this в setInterval() в первом из примеров?

var countup = {
    counter: 0,

    start:function(){
        var countup = this;
        setInterval(function(){
            countup.counter++;
        }, 1000);
    }
};

countup.start();

и

var countup = {
    counter: 0,

    start:function(){
        setInterval( () => {
            this.counter++;
        }, 1000);
    }
};

countup.start();

Обновление

Другой способ Задать мой вопрос можно было бы следующим образом:

Может кто-нибудь придумать хороший вариант использования this внутри setInterval()?

var countup = {
    counter: 0,

    start:function(){
        var countup = this;
        setInterval(function(){
            // insert good use case of `this` inside this function?
            countup.counter++;
        }, 1000);
    }
};

countup.start();

Ответы [ 3 ]

2 голосов
/ 16 апреля 2020

В первом примере вы присваиваете значение this, когда была определена функция startup , и присваиваете его переменной countup, и this в этот момент сохраняется в переменная countup, на которую ссылается замыкание, сформированное обратным вызовом в функции setInterval.

Если вы этого не сделаете, то в function this берется из контекст выполнения этой функции. Это означает, что когда setInterval будет запущен, this будет глобальным объектом, так как обратный вызов, переданный setInterval, выполняется в глобальном контексте:

var countup = {
  counter: 0,

  start: function() {
    setInterval(function() {
      //this is not the lexical this, but the context of execution
      //since this.counter is not defined, this would print NaN (undefined + 1 == NaN)
      this.counter++;
      console.log("this == window::true ", this == window, "this.counter::NaN:: ", this.counter);
    }, 1000);
  }
};

countup.start();

Во втором примере функция стрелка () => {}, предоставляемая для setInterval, всегда захватывает this из лексической области, поэтому this всегда связан. Таким образом, это работает правильно, без необходимости вручную захватывать this из лексической области видимости . Но обратите внимание, что обе являются анонимными функциями, т.е. не имеют свойства name, это поведение не имеет ничего общего с анонимным характером функций. Это то, как они определены, один определяется с помощью синтаксиса function, а другой - синтаксис функции стрелки.

Из документов Mozilla :

Функция стрелки не имеет этого собственного. Используется значение this лексической области видимости; Функции стрелок следуют нормальным правилам поиска переменных. Таким образом, при поиске этого, которого нет в текущей области видимости, функция стрелки заканчивает тем, что находила его из включенной области видимости.

1 голос
/ 17 апреля 2020

Я не думаю, что «наследовать» - правильное слово.

При каждом вызове функции присутствует скрытый this аргумент («значение this», иногда называемое «получатель»). Значение this зависит от того, как вызывается функция.

this был добавлен в язык для включения Java -подобного объектно-ориентированного синтаксиса. Например:

class Point {
  constructor(x, y) {
   this.x = x
   this.y = y
  }
  getX() {
    return this.x
  }
}

... или используя функцию конструктора:

function Point(x, y) {
  this._x = x
  this._y = y
}

Point.prototype.getX = function() {
  return this._x
}

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

const a = new Point(1, 2);
console.log(a.getX());

... но, к сожалению, есть дополнительная сложность вокруг this в JavaScript.

Сложность проистекает из способности вызывать функции другими способами, а не как метод объекта (подробности см. MDN ). Например:

function  myFunction() {
  console.log(this) // `undefined` in strict mode, `window` in non-strict
}
myFunction() // `myFunction` is not called as a method!

В первом примере приведен пример вызова функции иным способом, чем в методе: каким должно быть значение this в функции, предоставляемой в качестве обратного вызова для setInterval? Как это происходит, значение по умолчанию this в функциях, переданных в setInterval, является глобальным объектом (поэтому window в данном случае).

... и это объясняет идиому, который мы видим в используемом в Ваш код: присваивание значения this переменной that (я переименовал ее из "countup" в вашем примере) для обратного вызова, чтобы закрыться. Таким образом, мы можем ссылаться на значение this внешней лексической среды, начиная с внутри обратного вызова, всякий раз, когда он вызывается.

var countup = {
    counter: 0,
    start: function() {
        var that = this
        setInterval(function() {
            that.counter++
        }, 1000)
    }
}

Ваш второй пример делает то же самое, но в более современном JavaScript. Функции стрелок всегда используют значение this лексического окружения, в котором они объявлены («лексический this»). Таким образом, мы можем покончить с промежуточной переменной that:

var countup = {
    counter: 0,
    start: function() {
        setInterval(() => this.counter++, 1000)
    }
}

Внутри setInterval значение по умолчанию this является глобальным объектом, но ничто не мешает вам использовать другую эту значение с помощью функции стрелки или вызов , применение или связывание . Это просто ссылка на объект (или null, или undefined). Так что если есть общее состояние, которое вы хотите обновить с setInterval, то вы можете сделать это с помощью this. Является ли это хорошей идеей или нет, субъективно. Лично я стараюсь избегать this, потому что я думаю, что это усложняет ситуацию, но многие разработчики думают об обратном.

По моему опыту, this имеет тенденцию больше использоваться в кодовых базах, использующих объектную ориентацию на основе классов, поскольку в этих кодовых базах есть методы, которые часто должны ссылаться на состояние объекта, для которого они были вызваны.

class Clock {
  start() {
    setInterval(() => this.tick(Date()), 1000) // using lexical `this`!
  }
  tick(time) {
    console.log(time)
  }
}
const c = new Clock
c.start()
0 голосов
/ 16 апреля 2020

setInterval существует в глобальном / WindowOrWorkerGlobalScope , поэтому значение this связано с этим. Так как глобал уникален и доступен во всем скрипте, я не думаю, что будет какой-либо вариант использования для «связанной» функции с setInterval

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...