На эту тему уже есть несколько вопросов, и я посмотрел на все, что нашел - мой вопрос для того, чтобы прояснить для себя некоторые (очевидные) противоречия, которые я вижу. Я подозреваю, что есть лучшее решение, чем единственное, с которым я сейчас работаю. Я довольно новичок в Javascript.

Я прочитал правила обзора this, как описано, например, https://developer.mozilla.org/en- US / docs / Web / JavaScript / Справочник / Операторы / this. Из прочитанного я понимаю, что, хотя многое зависит от контекста вызова, если функция является методом объекта, то внутри функции this будет сам объект. Я думал, что это правило превосходит другие правила, но, возможно, я неправильно понял.

Я также прочитал пост на https: // medium.com/byte-sized-react/what-is-this-in-react-25c62c31480, который по сути говорит, что если я хочу получить доступ к состоянию объекта в методе через this, и у меня есть код лайк

class App extends Component {
  constructor(props) {
    super(props);
  }
  clickFunction() {
    console.log(this.props.value);
  }
  render() {
    return(
      <div onClick={this.clickFunction}>Click Me!</div>
    );
  }
}

Тогда мне нужно явно привязать объект к clickFunction(), либо добавив строку в конструктор, как

this.clickFunction = this.clickFunction.bind(this);

Или используя обозначение стрелки для определения clickFunction(), например

const clickFunction = () => { ... }

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

Например, есть учебник по React по адресу https://reactjs.org/tutorial/tutorial.html который определяет методы объекта, такие как renderSquare(i), и ни в коем случае не привязывает эти методы к объекту явно.

Если я попытаюсь сделать что-то, что мне кажется полностью аналогичным этому учебному пособию, и не буду явно добавлять строки в конструктор для привязки каждого метода к объекту, то есть такие строки, как this.clickFunction = this.clickFunction.bind(this), тогда я не смогу получить свой код для работы.

Может кто-нибудь объяснить мне, что я неправильно понимаю в учебнике и документации - почему учебник работает, даже если нет явной привязки к объекту? Единственное отличие, которое я могу заметить между этим и моим собственным кодом, состоит в том, что у меня есть use strict. Есть ли лучшее решение, чем решение this.clickFunction.bind(this), которое я сейчас использую? Добавление одной дополнительной строки кода в конструктор для каждого метода, чтобы явно связать все мои методы, кажется довольно неуклюжим.

0
user2428107 2 Май 2019 в 15:01

5 ответов

Лучший ответ

Функции со стрелками связывают ваши функции с вашим классом напрямую. Но когда, если вы используете

const clickFunction = () => { ... }

Это создаст внутреннюю функцию и не привязывает ее к классу.

Ты можешь использовать

clickFunction = () => { ... }

Который будет похож на

this.clickFunction = this.clickFunction.bind(this);

4
Harish 2 Май 2019 в 12:13

У вас есть действительные баллы

Почему учебник работал? Если вы увидите реализацию renderSquare, вы заметите, что она не использует this в своей реализации, поэтому ей не нужно связываться с этим. Ваша реализация может не работать, потому что вы можете использовать this внутри реализации метода.

renderSquare(i) {
  return <Square value={i} />;
}

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

См. Эту скрипку https://jsfiddle.net/yh3jw5nk/1/ для более подробного объяснения.

0
Saurabh Chouhan 2 Май 2019 в 12:33

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

const app = new App();
app.clickFunction();

Получил бы результат, который вы ожидаете, потому что он вызывается непосредственно из класса App.

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

const callback = app.clickFunction;
// click event happens
callback(event);

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

Два способа обойти это поведение, которые вы уже перечислили, явно устанавливают ключевое слово this для объекта, на котором они изначально живут. Вызов this.clickFunction = this.clickFunction.bind(this) является наиболее явным в том смысле, что он принимает обычную функцию и вручную связывает this со значением this во время создания объекта. Который будет строящимся объектом.

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

1
Erik Tate 2 Май 2019 в 12:32

Второй метод стрелки, он будет использовать эту ссылку, где метод определен не там, где он вызывается. так что возьмем эту ссылку класса.

Ссылка это в функции стрелки

0
Jitesh Manglani 2 Май 2019 в 12:11

Это определяется во время выполнения и, в зависимости от кода, может быть чем-то другим.

это

  • определяется во время выполнения, когда вызывается функция
  • определяется тем, как вызывается функция, а не где функция определена
  • ссылка на объект.
  • всегда будет объектом
  • глобальный (это) не доступен в строгом режиме

Пример 1: this = window

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  //console.log(this);
  callName2();
}


var callName2 = function() {
  var name = 'Jane';
  console.log('--- From callName2 ----');
  console.log(this.name);
  //console.log(this);
}

callName1();

var execute = function(fn) {
  var name = 'Mary';
  console.log('--- From execute ----');
  console.log(this.name);
  //console.log(this);
}

execute(callName2);

Пример 2: недоступен в строгом режиме

'use strict';

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  console.log(this);
}

callName1();

Пример 3: проверка this с помощью вызова метода

var name = 'global';

var obj = {
  name: 'James Obj1',
  func: function() {
    console.log('--- From func ----');
    console.log(this.name);
    console.log(this); // this reference obj1
  }
}

obj.func()

var obj2 = {
  name: 'Jame Obj2',
  func: obj.func // this reference obj2, but the function is defined in obj1
}

obj2.func()

var obj3 = {
  name: 'Kane Obj3',
  obj4: {
    name: 'Mary Obj4',
    func: function () {
      console.log('--- From obj4 ----');
      console.log(this.name);
      console.log(this); // this reference obj4
    }
  }
}
obj3.obj4.func()

С () => {} функцией this - лексически связан. Это означает, что он использует this из кода, который содержит функцию стрелки.

0
Junius L. 2 Май 2019 в 13:13