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


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.