Можете ли вы связать это в стрелочной функции?

134

Я уже некоторое время экспериментирую с ES6 и только что столкнулся с небольшой проблемой.

Мне очень нравится использовать стрелочные функции, и я использую их всякий раз, когда могу.

Однако, похоже, их нельзя связать!

Вот функция:

var f = () => console.log(this);

Вот объект, к которому я хочу привязать функцию:

var o = {'a': 42};

И вот как я бы привязался fк o:

var fBound = f.bind(o);

И тогда я могу просто позвонить fBound:

fBound();

Что выведет это ( oобъект):

{'a': 42}

Прохладно! Прекрасный! Только вот это не работает. Вместо вывода oобъекта он выводит windowобъект.

Итак, я хотел бы знать: можно ли привязать стрелочные функции? (И если да, то как?)


Я протестировал приведенный выше код в Google Chrome 48 и Firefox 43, и результат тот же.

Флори
источник
29
Весь смысл стрелочных функций в том, что они используют thisобъект своей родительской области.
loganfsmyth

Ответы:

159

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

Из спецификации ECMAScript 2015 :

Любая ссылка на arguments, super, this или new.target внутри ArrowFunction должна разрешаться в привязку в лексически включающей среде. Обычно это будет функциональная среда непосредственно включающей функции.

Ник Томлин
источник
7
Первое предложение этого ответа неверно. Наверное потому, что вопрос тоже сбивает с толку привязка и this. Эти два понятия связаны, но не одно и то же. thisвнутри стрелочной функции всегда «наследует» thisиз окружающей области видимости. Это особенность стрелочных функций. Но вы все равно можете использовать bindвсе остальные параметры стрелочной функции. Просто нет this.
Stijn de Witt
54

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

bind все еще имеет значение для аргументов функции:

((a, b, c) => {
  console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()

Попробуйте здесь: http://jsbin.com/motihanopi/edit?js,console

cvazac
источник
1
Есть ли способ обнаружить или использовать любой объект, к thisкоторому привязана функция (стрелка), без ссылки (что, конечно, определяется лексически)?
Флори,
3
Используйте аргумент для контекста: ((context) => {someOtherFunction.apply (context)}). Bind (willBeIgnored, context) ()
cvazac
13

Из MDN :

Выражение функции стрелки имеет более короткий синтаксис по сравнению с выражениями функций и лексически связывает значение this (не связывает свои собственные this, arguments, super или new.target). Стрелочные функции всегда анонимны.

Это означает, что вы не можете привязать значение так, thisкак хотите.

Стерлинг Арчер
источник
6

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

Все это заставляет меня спрашивать, почему, почему! почему бы вам не перепривязать стрелочную функцию! Те, которые созданы специально, чтобы решить все эти проблемы и недоразумения и избежать необходимости использовать bindили callили любой другой способ сохранить объем функции.

TL; DR

Нет, вы не можете повторно привязать стрелочные функции.

taxicala
источник
7
Стрелочные функции были созданы прежде всего для обеспечения более чистого и быстрого синтаксиса. Подумайте о лямбда-исчислении. Жаль, что фанатики объектно-ориентированного программирования, донимающие жизнь функциональных JS-программистов, ухватились за возможность лишить свободы указывать контекст вызова.
Марко Фаустинелли
5
Использование thisне работает. лямбды должны быть arguments => output. Если вам нужен какой-то внешний контекст, передайте его. Само существование this- это то, что облегчило все внедрение объектно-ориентированных шаблонов в язык. Без него вы бы никогда не услышали термин «класс javascript».
erich2k8
3
Вы можете повторно привязать стрелочные функции. Просто нет this.
Stijn de Witt
6

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

Здесь мы используем evalвызов, чтобы воссоздать функцию стрелки, которую вы передали как обычную функцию, а затем использовать callдля ее вызова с другим this:

var obj = {value: 10};
function arrowBind(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBind(obj, () => {console.log(this)});

имя
источник
3
Спасибо, что поделились этим примером способа привязки стрелочной функции к другому контексту! Чтобы сделать ответ более понятным для будущих читателей, возможно, вы могли бы отредактировать его, чтобы описать, как и почему работает код?
Florrie
4

Действительно ли стрелочные функции ES6 решают «это» в JavaScript

Приведенная выше ссылка объясняет, что функции стрелок thisне меняются вместе с bind, call, applyфункциями.

Это объясняется на очень хорошем примере.

запустите это, node v4чтобы увидеть "ожидаемое" поведение,

this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){ 
    // bind the value of "this" on the method 
    // to try and force it to be what you want 
    this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar(); 
Притхви Радж Вуппалапати
источник
Просьба предоставить более релевантную информацию в самом ответе, это может быть образец кода или отредактированные версии вопросов
Jithin Scaria
// запускаем это в узле v4, чтобы увидеть "ожидаемое" поведение this.test = "при подключении к модулю"; var foo = {тест: "прикреплен к объекту"}; foo.method = function (name, cb) {// привязываем значение this к методу // чтобы попытаться заставить его быть тем, что вы хотите this [name] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); foo.bar ();
Prithvi Raj Vuppalapati 02
Здесь интересно попробовать это, а затем повторить попытку, заменив foo.method ('bar', () => {console.log (this.test);}); с помощью foo.method ('bar', function () {console.log (this.test);}); - журналы первой версии «прикреплены к модулю», а журналы второй версии «прикреплены к объекту» - я действительно предпочитаю более стабильную обработку «этого» с помощью стрелочных функций. Вы все еще можете добиться других эффектов, используя другие шаблоны, и результаты будут более читаемыми и предсказуемыми IMO.
Methodician
3

Я задал тот же вопрос пару дней назад.

Вы не можете привязать значение, так как thisоно уже привязано.

Связывание другой этой области с ES6 => оператор функции

fos.alex
источник
4
«поскольку this уже привязан» - в обычных функциях thisтоже привязан. Дело в том, что в стрелочных функциях он не имеет локальной привязки.
Лучше Оливер
2

Короче говоря, вы НЕ МОЖЕТЕ привязать стрелочные функции, но читайте дальше:

Представьте, что у вас есть эта стрелочная функция, под которой печатается thisна консоли:

const myFunc = ()=> console.log(this);

Таким образом, для быстрого решения этой проблемы будет использоваться обычная функция, поэтому просто измените ее на:

function myFunc() {console.log(this)};

Затем вы можете привязать его к любой лексической среде, используя bindили callили apply:

const bindedFunc = myFunc.bind(this);

и назовите его в случае bind.

bindedFunc();

Существуют также способы использования eval(), которые настоятельно не рекомендуются .

Алиреза
источник
function myFuncотличается в поведении не только в том, что его можно связывать; был бы более близкий матч const myFunc = function() {...}. Мне также любопытно, что вы имеете в виду, говоря об использовании eval, поскольку я не думаю, что это подход, в котором раньше делились какие-либо ответы - было бы интересно посмотреть, как это делается, а затем прочитать, почему это так сильно не рекомендуется.
Флорри
1

Может быть, вам поможет этот пример:

let bob = {
   _name: "Bob",
   _friends: ["stackoverflow"],
   printFriends:(x)=> {
      x._friends.forEach((f)=> {
         console.log(x._name + " knows " + f);
      });
   }
}

bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();

Ehsan
источник
gøød stuff ... мягко говоря интересно
Aleks