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


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


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

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


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 => оператор функции


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();


gøød stuff ... мягко говоря интересно
— Aleks
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.