Каковы различия (если они есть) между функциями стрелок ES6 и функциями, связанными с Function.prototype.bind?
Мне кажется, что в ES6 следующие две функции очень близки:
function () {
return this;
}.bind(this);
() => {
return this;
};
Конечный результат выглядит одинаково: функции-стрелки создают объект функции JavaScript со своим контекстом this
, связанным с тем же значением, что и this
, где они созданы.
Очевидно, что в общем смысле Function.prototype.bind
является более гибким, чем функции стрелок: он может связываться со значениями, отличными от локального this
, и он может связывать любую функцию this
в любой момент времени, потенциально долго после его создания. Тем не менее, я не спрашиваю, как bind
сам отличается от функций стрелок, я спрашиваю, как функции стрелок отличаются от непосредственного вызова bind
с помощью this
.
Существуют ли различия между двумя конструкциями в ES6?
Ответы
Ответ 1
Нет (существенных) различий.
Хорошо, ладно, это немного преждевременно. Существуют три крошечных отличия, уникальные для функций стрелок.
-
Функции стрелок не могут использоваться с new
.
Это означает, конечно, что они не имеют свойства prototype
и не могут быть использованы для создания объекта с классическим вдохновляющим синтаксисом.
new (() => {}) // TypeError: () => {} is not a constructor
Это, вероятно, самое лучшее, но способ new
не имеет особого смысла в связанных функциях.
-
Функции стрелок не имеют доступа к специальному объекту arguments
, к которому имеют доступ обычные функции JavaScript.
(() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
Это, вероятно, немного больше. Предположительно, это удалить один из JavaScript других странностей. Объект arguments
- это собственный особый зверь, и он имеет странное поведение, поэтому неудивительно, что он был брошен.
Вместо этого ES6 имеет значки, которые могут выполнять одно и то же без волшебных скрытых переменных:
((...args) => args)(1, 2, 3) // [1, 2, 3]
-
Функции стрелок не имеют своего собственного свойства new.target
, они используют new.target
их закрывающей функции, если она существует.
Это согласуется с другими изменениями, чтобы удалить "волшебные" введенные значения для функций стрелок. Это особое изменение особенно очевидно, поскольку функции стрелок не могут использоваться с new
в любом случае, как упоминалось выше.
В противном случае стрелки похожи на связанные функции, семантически. Это позволяет стрелкам быть более совершенными, так как им не нужно носить с собой дополнительный багаж, и, поскольку сначала они не должны быть преобразованы из обычных функций, но они поведенчески одинаковы.
Ответ 2
Есть несколько отличий:
-
Функции стрелок не могут быть построены. Хотя обе функции стрелок и связанные функции оба не имеют свойства .prototype
, первые вызывают исключение при вызове с помощью new
, в то время как последние просто игнорируют связанное значение и вызывают их целевую функцию как конструктор (частично применяемые связанные аргументы, хотя) в новом экземпляре.
function F() {}
var f = () => {},
boundF = F.bind({});
console.log(new boundF(), new boundF instanceof F) // {}, true
console.log(new f) // TypeError
-
Функции стрелок имеют лексические arguments
, new.target
и super
(не только лексические this
). Вызов функции стрелки не инициализирует ни один из них, они просто наследуются от функции, в которой была указана функция стрелки. В связанной функции они просто ссылаются на соответствующие значения целевой функции.
-
Функции стрелки фактически не привязывают значение this
. Скорее, у них их нет, и когда вы используете this
, он рассматривается как имя переменной в лексической области. Это позволяет вам лениво определять функцию стрелки, а this
еще не доступно:
class X extends Object {
constructor() {
var f = () => this, // works
boundF = function(){ return this; }.bind(this);
// ^^^^ ReferenceError
super(); // initialises `this`
console.log(f(), f() == this); // {}, true
}
}
new X;
-
Функции стрелок не могут быть функциями генератора (хотя они могут возвращать генераторы). Вы можете использовать .bind()
для функции генератора, но нет возможности выразить это с помощью функции стрелки.
Ответ 3
Вот еще одно тонкое различие:
Функции Arrow могут возвращать функцию без использования ключевого слова 'return', опустив скобки {}, следующие за = > .
var f=x=>x; console.log(f(3)); // 3
var g=x=>{x}; console.log(g(3)); // undefined
var h=function(x){x}; console.log(h(3)); // undefined
var i=x=>{a:1}; console.log(i(3)); // undefined
var j=x=>({a:1}); console.log(j(3)); // {a:1}