Каковы различия (если они есть) между функциями стрелок 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}