Согласно предложению, стрелки нацелены на устранение нескольких общих проблем традиционных функциональные выражения. Они намеревались улучшить положение за счет 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 (вчера ~ 120k загрузок) предоставляет методы для своих тестов через
this
.
- Grunt (вчера ~ 63k загрузок) предоставляет методы для задач сборки через
this
.
- Backbone (вчера ~ 22k загрузок) определяет методы доступа к
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 parentheses
Блоки выглядят как объекты:
(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
переменной. Не используйте () => {}
.
person
Jackson
schedule
25.01.2015
Fixed this bound to scope at initialisation
ограничением? - person thefourtheye   schedule 08.04.2014this
- это то, что вы можете делать с обычными функциями, но не со стрелочными функциями. - person lyschoening   schedule 08.04.2014Fixed this bound to scope at initialisation
является ограничением. :) Взгляните на эту статью: explorejs.com/es6/ch_arrow-functions.html а> - person NgaNguyenDuy   schedule 05.02.2016Fixed this bound to scope at initialisation
также известна как лексическая привязка - person Iven Marquardt   schedule 10.03.2016