Згідно з пропозицією , стрілки спрямовані на "вирішення та усунення декількох загальних больових точок традиційних Function Expression
". Вони мали намір покращити питання, this
лексично зв’язуючи та пропонуючи короткий синтаксис.
Однак,
- Не можна послідовно пов'язувати
this
лексично
- Синтаксис функції стрілки тонкий і неоднозначний
Тому функції стрілок створюють можливості для плутанини та помилок, і їх слід виключати зі словника програміста JavaScript, замінювати function
виключно.
Щодо лексичного this
this
проблематично:
function Book(settings) {
this.settings = settings;
this.pages = this.createPages();
}
Book.prototype.render = function () {
this.pages.forEach(function (page) {
page.draw(this.settings);
}, this);
};
Функції стрілки мають намір вирішити проблему, коли нам потрібно отримати доступ до властивості this
всередині зворотного дзвінка. Існує вже кілька способів зробити це: можна призначити this
змінну, використовувати bind
або використовувати третій аргумент, доступний для Array
методів сукупності. Однак стрілки здаються найпростішим способом вирішення, тому метод може бути відновлений так:
this.pages.forEach(page => page.draw(this.settings));
Однак врахуйте, чи використовувався в коді бібліотеку типу jQuery, чиї методи this
спеціально пов'язуються . Тепер this
слід вирішити два значення:
Book.prototype.render = function () {
var book = this;
this.$pages.each(function (index) {
var $page = $(this);
book.draw(book.currentPage + index, $page);
});
};
Ми повинні використовувати function
для того, each
щоб this
динамічно зв’язувати . Тут ми не можемо використовувати функцію стрілки.
Зв'язок з декількома this
значеннями також може бути заплутаним, оскільки важко знати, this
про кого говорив автор:
function Reader() {
this.book.on('change', function () {
this.reformat();
});
}
Чи насправді автор мав намір подзвонити Book.prototype.reformat
? Або він забув зв’язати this
, і мав намір подзвонити Reader.prototype.reformat
? Якщо ми змінимо обробник на функцію стрілки, ми будемо аналогічно задаватися питанням, чи бажав автор динаміки this
, але вибрав стрілку, оскільки вона вміщується в одному рядку:
function Reader() {
this.book.on('change', () => this.reformat());
}
Можна поставити: "Чи винятковим є те, що стрілки іноді можуть бути неправильною функцією для використання? Можливо, якщо нам дуже рідко потрібні динамічні this
значення, то все одно було б добре використовувати стрілки більшу частину часу".
Але запитайте себе так: "Чи варто" вартувати "налагодження коду та виявити, що результат помилки спричинив" кращий випадок? " 100% часу.
Є кращий спосіб: завжди використовувати function
(тому this
завжди можна динамічно зв'язати) та завжди посилатися this
через змінну. Змінні лексичні і припускають багато назв. Призначення this
змінної дозволить зрозуміти ваші наміри:
function Reader() {
var reader = this;
reader.book.on('change', function () {
var book = this;
book.reformat();
reader.reformat();
});
}
Крім того, завжди присвоєння this
змінної (навіть коли є одна this
чи відсутність інших функцій) забезпечує певні наміри залишатися зрозумілими навіть після зміни коду.
Також динаміка this
навряд чи є винятковою. jQuery використовується на понад 50 мільйонах веб-сайтів (станом на цей текст у лютому 2016 року). Ось інші API, що this
динамічно прив’язуються :
- Mocha (~ 120 к завантажень вчора) розкриває методи своїх тестів через
this
.
- Grunt (~ 63 к завантаження вчора) розкриває методи складання завдань через
this
.
- Хребет (~ 22 к. Завантажень вчора) визначає методи доступу
this
.
- API - інтерфейси подій (як і DOM - х) відносяться до
EventTarget
з this
.
- Прототипні API, які виправлені або розширені, посилаються на екземпляри з
this
.
(Статистика через http://trends.builtwith.com/javascript/jQuery та https://www.npmjs.com .)
Вам, швидше за все, потрібні динамічні this
прив’язки.
Лексика this
іноді очікується, але іноді ні; так само, як this
іноді очікується динаміка , але іноді ні. На щастя, є кращий спосіб, який завжди виробляє та повідомляє очікуване прив'язування.
Щодо короткого синтаксису
Функції стрілок досягли «коротшої синтаксичної форми» для функцій. Але чи зроблять вас ці коротші функції більш успішними?
Чи x => x * x
"легше читати", ніж function (x) { return x * x; }
? Можливо, це так, тому що швидше створити єдиний короткий рядок коду. Прихильність до Дайсона Вплив швидкості читання та довжини рядка на ефективність читання з екрана ,
Середня довжина рядка (55 символів на рядок), як видається, підтримує ефективне читання при нормальній та швидкій швидкості. Це призвело до найвищого рівня розуміння. . .
Аналогічні обґрунтування зроблені для умовного (потрійного) оператора та для однорядкових if
операторів.
Однак ви справді пишете прості математичні функції, рекламовані у пропозиції ? Мої домени не є математичними, тому мої підпрограми рідко такі елегантні. Швидше за все, я бачу, як функції стрілок порушують ліміт стовпців і переходять на інший рядок завдяки редактору чи посібнику зі стилів, який зводить нанівець "читабельність" за визначенням Дайсона.
Можна поставити запитання: "Як щодо використання короткої версії для коротких функцій, коли це можливо?" Але тепер стилістичне правило суперечить мовному обмеженню: "Спробуйте використовувати найкоротші можливі позначення функцій, пам’ятаючи, що іноді лише найдовші позначення пов'язуватимуть, this
як очікувалося". Така плутанина робить стрілки особливо схильними до неправильного використання.
Існує чимало проблем із синтаксисом функції стрілки:
const a = x =>
doSomething(x);
const b = x =>
doSomething(x);
doSomethingElse(x);
Обидві ці функції синтаксично дійсні. Але doSomethingElse(x);
це не в тілі b
, це лише погано відрезане твердження верхнього рівня.
Розширюючись до форми блоку, більше не існує неявного return
, який можна було б забути відновити. Але вираз може тільки було призначене для отримання побічного ефекту, так що хто знає , якщо явно return
необхідно буде йти вперед?
const create = () => User.create();
const create = () => {
let user;
User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
const create = () => {
let user;
return User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
Те, що може бути призначено як параметр відпочинку, може бути проаналізовано як оператор розповсюдження:
processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest
Призначення можна переплутати з аргументами за замовчуванням:
const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parens
Блоки мають вигляд об’єктів:
(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object
Що це означає?
() => {}
Чи мав намір автор створити неопераційний або функцію, яка повертає порожній об’єкт? (Маючи це на увазі, чи слід коли-небудь розміщувати {
після цього =>
? Чи слід обмежуватися лише синтаксисом виразів? Це ще більше зменшить частоту стрілок.)
=>
виглядає <=
і >=
:
x => 1 ? 2 : 3
x <= 1 ? 2 : 3
if (x => 1) {}
if (x >= 1) {}
Щоб негайно викликати вираз функції стрілки, її потрібно розміщувати ()
зовні, але розміщення ()
на внутрішній стороні є дійсним і може бути навмисним.
(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function
Хоча, якщо писати (() => doSomething()());
з наміром написати вираз функції, що негайно викликається, просто нічого не станеться.
Важко стверджувати, що функції стрілок «зрозуміліші», маючи на увазі всі вищезазначені випадки. Можна було б вивчити всі спеціальні правила, необхідні для використання цього синтаксису. Чи справді це варто?
Синтаксис function
винятково узагальнений. Використовувати function
виключно засоби, сама мова заважає писати заплутаний код. Писати процедури, які слід синтаксично розуміти у всіх випадках, я вибираю function
.
Щодо настанови
Ви вимагаєте керівництва, яке повинно бути "чітким" та "послідовним". Використання функцій зі стрілками в кінцевому підсумку призведе до синтаксично допустимого, логічно недійсного коду, причому обидві форми функцій переплітаються, значущо та довільно. Тому я пропоную наступне:
Керівництво для функцій нотації в ES6:
- Завжди створюйте процедури за допомогою
function
.
- Завжди призначати
this
змінну. Не використовуйте () => {}
.
Fixed this bound to scope at initialisation
обмеженням?