Чи можете ви пов’язати "це" у функції стрілки?


133

Я деякий час експериментував з 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

Відповіді:


158

Ви не можете перезапустити this функцію стрілки. Він завжди визначатиметься як контекст, в якому він був визначений. Якщо вам потрібно thisбути значущим, вам слід скористатися нормальною функцією.

З специфікації ECMAScript 2015 :

Будь-яке посилання на аргументи, супер, цей або new.target у ArrowFunction повинно вирішуватись до прив'язки у лексично оточуючому середовищі. Зазвичай це буде функціональне середовище функції, що негайно вкладається.


7
Перше речення цієї відповіді неправильне. Можливо, тому, що питання також бентежить обов'язковість і this. Два пов'язані, але не однакові. thisвсередині функції стрілки завжди 'успадковує' thisз області, що додається. Це особливість функцій стрілок. Але ви можете все ж bindінші параметри функції стрілки. Просто ні this.
Штійн де Вітт

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 :

Вираз функції стрілки має коротший синтаксис порівняно з виразами функцій і лексично пов'язує це значення (не пов'язує його власне це, аргументи, супер або new.target). Функції стрілок завжди анонімні.

Це означає, що ви не можете прив’язати значення до того, thisяк хочете.


6

Протягом багатьох років розробники js боролися з контекстною прив'язкою, запитували, чому thisзмінилося в JavaScript, стільки плутанини за ці роки через контекстну прив'язку та різницю між значенням thisу javascript та thisбільшості інших мов OOP.

Все це змушує мене запитати, чому, чому! чому б ви не хотіли відновлювати функцію стрілки! Ті , де створені спеціально , щоб вирішити всі ці проблеми і негаразди і уникнути необхідності використовувати bindабо callбудь-якої іншої спосіб , щоб зберегти сферу функції.

TL; DR

Ні, ви не можете відновити функції стрілок.


7
Функції стрілок були створені насамперед для забезпечення більш чіткого та швидкого синтаксису. Подумайте лямбда-числення. Шкода, що OO-завзятці, які загрожують життю функціональних програмістів JS, захопили можливість позбавити свободу для визначення контексту виклику.
Марко Фаустінеллі

5
Використання thisне є функціональним. лямбда повинні бути arguments => output. Якщо вам потрібен якийсь зовнішній контекст, вкажіть його. Саме існування - thisце те, що полегшило введення всіх мов OO в мову. Ви ніколи не чули б терміна "javascript class" без нього.
erich2k8

3
Ви можете відновити функції стрілок. Просто ні this.
Штійн де Вітт

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
Дякуємо, що поділилися цим прикладом способу прив’язки функції стрілки до іншого контексту! Щоб відповісти простіше зрозуміти майбутнім читачам, можливо, ви могли б відредагувати її, щоб описати, як і чому працює код?
Флорі

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 = {test: "приєднано до об'єкта"}; foo.method = функція (ім'я, cb) {// прив'язує значення "this" у методі //, щоб спробувати примусити його бути таким, яким ви цього хочете [name] = cb.bind (this); }; foo.method ("бар", () => {console.log (this.test);}); foo.bar ();
Прітві Радж Вуппалапаті

Що цікавого тут - спробувати це, а потім спробувати знову замінити foo.method ('bar', () => {console.log (this.test);}); з foo.method ('bar', function () {console.log (this.test);}); - перші журнали версій, "прикріплені до модуля", а другі - "приєднані до об'єкта", - я дійсно віддаю перевагу більш стабільній обробці "цього" за допомогою функцій стрілок. Ви можете досягти інших ефектів, використовуючи різні шаблони, і результати є більш читабельними та прогнозованими ІМО.
Methodician

3

Я задав те саме питання пару днів тому.

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

Прив’язування різної цієї сфери до оператора функції ES6 =>


4
"оскільки це вже пов'язане" - У звичайних функціях 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();


дивляться речі ... м'яко цікаві
Алекс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.