Функция стрелки против объявления / выражения функции: они эквивалентны / заменяемы?
канонический вопрос если вы нашли вопрос о проблемах после замены объявления / выражения функции функцией стрелки, пожалуйста, закройте его как дубликат этого.
функции стрелки в ES2015 обеспечивают более сжатый синтаксис. Могу ли я теперь заменить все мои объявления / выражения функций функциями стрелки? На что я должен обратить внимание?
примеры:
конструктор функция
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
методы прототипа
User.prototype.getName = function() {
return this.name;
};
// vs
User.prototype.getName = () => this.name;
2 ответов:
tl; dr:нет! функции стрелок и объявления / выражения функций не эквивалентны и не могут быть заменены вслепую.
Если функция, которую вы хотите заменить ли не использоватьthis,argumentsи сnew, тогда да.
как это часто бывает:зависит. Функции стрелки имеют другое поведение, чем объявления / выражения функций, поэтому давайте посмотрим на различия первый:
1. Лексический
thisиargumentsфункции стрелки не имеют своих собственных
thisилиargumentsпривязка. Вместо этого эти идентификаторы разрешаются в лексической области, как и любая другая переменная. Это означает, что внутри функции стрелки,thisиargumentsотносятся к ценностямthisиargumentsв окружающей среде функция стрелки определена in (т. е. "снаружи" стрелка функция):// Example using a function expression function createObject() { console.log('Inside `createObject`:', this.foo); return { foo: 42, bar: function() { console.log('Inside `bar`:', this.foo); }, }; } createObject.call({foo: 21}).bar(); // override `this` inside createObject// Example using a arrow function function createObject() { console.log('Inside `createObject`:', this.foo); return { foo: 42, bar: () => console.log('Inside `bar`:', this.foo), }; } createObject.call({foo: 21}).bar(); // override `this` inside createObjectв случае выражения функции
thisотносится к объекту, который был создан внутриcreateObject. В случае функции стрелки,thisотносится кthisнаcreateObjectсам по себе.это делает функции стрелки полезными, если вам нужно получить доступ к
thisтекущей среды:// currently common pattern var that = this; getData(function(data) { that.data = data; }); // better alternative with arrow functions getData(data => { this.data = data; });Примечание что это также означает, что не можно установить функцию стрелки
thisС.bindили.call.если вы не очень хорошо знакомы с
this, вы можете прочитать2. Функции стрелки не могут быть вызваны с помощью
newES2015 различает функции вызовсостоянии и функции построитьсостоянии. Если функция является конструктивной, ее можно вызвать с помощью
new, т. е.new User(). Если функция может быть вызвана, она может быть вызвана безnew(т. е. обычный вызов функции).функции, созданные с помощью объявлений / выражений функций, являются как конструктивными, так и вызываемыми.
Функции стрелки (и методы) только вызываются.classконструкторы являются только конструктивными.если вы пытаетесь вызвать a не вызываемая функция или построить неконструктивную функцию, вы получите ошибку времени выполнения.
зная это, мы можем заявить следующее.
заменить:
- функции, которые не используете
thisилиarguments.- функции, которые используются с
.bind(this)не заменить:
- функции конструктора
- функция / методы, добавленные в a прототип (потому что они обычно используют
this)- функции с переменным числом аргументов (если они используют
arguments(см. ниже))
давайте более подробно рассмотрим это, используя ваши примеры:
функции-конструктора
это не будет работать, потому что функции стрелки не могут быть вызваны с
new. Продолжайте использовать объявление / выражение функции или используйтеclass.прототип методы
скорее всего нет, потому что методы прототипа обычно использую
thisдля доступа к экземпляру. Если они не используютthis, то вы можете заменить его. Однако, если вы в первую очередь заботитесь о кратком синтаксисе, используйтеclassС его кратким синтаксис метода:class User { constructor(name) { this.name = name; } getName() { return this.name; } }методы объекта
аналогично для методов в объектном литерале. Если метод хочет ссылаться на сам объект через
this, продолжайте использовать выражения функций, или используйте новый синтаксис метода:const obj = { getName() { // ... }, };обратные вызовы
это зависит. Вы обязательно должны заменить его, если вы сглаживаете внешний
thisили.bind(this):// old setTimeout(function() { // ... }.bind(this), 500); // new setTimeout(() => { // ... }, 500);но: если код, который вызывает обратный вызов явно устанавливает
thisк определенному значению, как это часто бывает с обработчиками событий, особенно с jQuery, и обратный вызов используетthis(илиarguments), то не может использовать функция стрелки!variadic функции
так как функции стрелки не имеют своих собственных
arguments, вы не можете просто заменить их функцию стрелки. Тем не менее, ES2015 представляет альтернативу использованиюarguments: the параметра.// old function sum() { let args = [].slice.call(arguments); // ... } // new const sum = (...args) => { // ... };
вопрос:
- когда я должен использовать функции стрелки в ECMAScript 6?
- Do ES6 функции стрелки имеют свои собственные аргументы или нет?
- каковы различия (если таковые имеются) между функциями стрелки ES6 и функциями, связанными с функцией.прототип.связывать?
- как использовать стрелку ES6 в методах класса?
дополнительные ресурсы:
посмотрите на этот пример Plnkr
переменная
thisочень разныеtimesCalledувеличивается только на 1 при каждом вызове кнопки. Что отвечает на мой личный вопрос:
.click( () => { } )и
.click(function() { })оба создают одинаковое количество функций при использовании в цикле, как вы можете видеть из счетчика Guid в Plnkr.
Comments