Каковы различия (если таковые имеются) между функциями стрелок ES6 и функциями, связанными с Function.prototype.bind?

Мне кажется, что в ES6 следующие две функции почти идентичны:

function () {
  return this;
}.bind(this);

() => {
  return this;
};

Конечный результат выглядит одинаково: функции со стрелками создают объект функции JavaScript со своими this контекст привязан к тому же значению, что и this где они созданы.

Очевидно, в общем смысле Function.prototype.bind более гибок, чем функции стрелок: он может связываться со значениями, отличными от локальных thisи может связать любую функцию this в любой момент времени, потенциально еще долго после его создания. Тем не менее, я не спрашиваю, как bind само по себе отличается от функций со стрелками, я спрашиваю, как функции со стрелками отличаются от непосредственного вызова bind с this,

Есть ли различия между двумя конструкциями в ES6?

3 ответа

Нет (значительных) различий.

Ну, хорошо, это немного преждевременно. Есть три крошечных различия, уникальных для функций стрелок.

  1. Функции стрелок нельзя использовать с new,

    Это означает, конечно, что они не имеют prototype свойство и не может использоваться для создания объекта с классическим синтаксисом.

    new (() => {}) // TypeError: () => {} is not a constructor
    

    Это, вероятно, к лучшему, хотя new Работы не будут иметь большого смысла со связанными функциями.

  2. Функции стрелок не имеют доступа к специальным arguments объект, к которому имеют доступ обычные функции JavaScript.

    (() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
    

    Этот, вероятно, немного больше гоча. Предположительно это сделано для того, чтобы убрать одну из других странностей JavaScript. arguments объект - это свое особое чудовище, и у него странное поведение, поэтому неудивительно, что его выбросили.

    Вместо этого в ES6 есть знаки, которые могут выполнить то же самое без каких-либо волшебных скрытых переменных:

    ((...args) => args)(1, 2, 3) // [1, 2, 3]
    
  3. Функции стрелок не имеют своих new.target собственность, они используют new.target их вмещающей функции, если она существует.

    Это согласуется с другими изменениями для удаления "магически" введенных значений для функций стрелок. Это конкретное изменение особенно очевидно, учитывая, что функции стрелок нельзя использовать с new во всяком случае, как упоминалось выше.

В противном случае стрелки семантически подобны связанным функциям. Стрелки могут быть более производительными, так как им не нужно носить с собой дополнительный багаж и их не нужно сначала преобразовывать из обычных функций, но по поведению они точно такие же.

Есть несколько отличий:

  • Функции стрелок не могут быть построены. В то время как функции со стрелками и связанные функции не имеют .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() на функции генератора, но нет способа выразить это с помощью функции стрелки.

Вот еще одно тонкое отличие:

Функции со стрелками могут возвращать значение без использования ключевого слова 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}
Другие вопросы по тегам