Подтвердить что ты не робот

Что означает `bind.bind`? Странный способ использования привязки JavaScript

Я читаю книгу о написании фреймворков JavaScript и нашел этот фрагмент кода. Но я не понимаю, как это работает, особенно использование bind.bind? Кто-нибудь знает?

var bind = Function.prototype.bind;
var apply = bind.bind(bind.apply);
var fn = apply([].concat);
var a = [1, 2, 3], b = [4, [5, 6], 7];
fn(a, b);
//output [1, 2, 3, 4, 5, 6, 7]
4b9b3361

Ответ 1

Это возвращает меня к дням решения и расширения уравнений.

1. Во-первых, давайте разворачиваем первую применимую функцию:

var bind = Function.prototype.bind;
var apply = bind.bind(bind.apply);
var fn = apply([].concat);

Преобразовывает в:

var apply = Function.prototype.bind.bind(Function.prototype.bind.apply);
var fn = apply([].concat)

2. Во-вторых, мы расширяем функцию fn:

var fn = Function.prototype.bind.bind(Function.prototype.bind.apply)([].concat);

3. Теперь мы выработаем правило алгебры js и заменим вызов bind.bind...() вызовом вызова.

На самом деле мы реализуем базу замены на понятии, что:

someFunction.bind(arg1)(arg2) <==> someFunction.call(arg1, arg2)

Поэтому мы можем заменить это и получить:

var fn = Function.prototype.bind.call(Function.prototype.bind.apply, [].concat);

4. Для нашего второго правила алгебры js мы разрабатываем следующее:

someFn.bind.call(target, ...) <==> target.bind(...).

someFn здесь не важен, потому что мы не называем bind() на нем. Мы вызываем call на bind - заменяя this, который был someFn, и поэтому он заменяется на target.

Поэтому мы заменяем bind.call(target) альтернативой target.bind

var fn = Function.prototype.bind.apply.bind([].concat) 

5. Если последняя перестановка также выполняла invocation(), мы могли бы сделать замену как:

fn([1, 2], [3, 4]) <==> [].concat.apply([1, 2], [3, 4])

Но у нас есть только привязка без вызова, которую мы можем заменить, и эквивалентна:

var fn = function (arg1, arg2) { 
    return [].concat.apply(arg1, arg2); 
}
// instead arg1 and arg2 we could use more accurate arguments logic also.

Конечный результат

var fn = Function.prototype.bind.apply.bind([].concat) 

// or

var fn = function (arg1, arg2) { 
    return [].concat.apply(arg1, arg2); 
}

Функция fn принимает функцию concat и позволяет нам использовать ее в функциональном стиле, не вызывая ее из объекта. Вместо concat, привязанного к this вызывающего, fn применяет его к arg1 как this и arg2 как другие параметры для конкатенации arg1.

fn([1, 2], [3, [5, 6], 4])
// [1, 2, 3, 5, 6, 4]

Ответ 2

Поскольку Function.prototype.bind сам является функцией, он наследует себя как метод.

Как правило, bind вызывается как метод экземпляра для определенной функции, но мы можем переустановить его на Function.prototype.apply и вернуть функцию более высокого порядка.

Менее простой способ записи:

function apply (fn) {
  return function (a, b) {
    return fn.apply(a, b)
  }
}

Ответ 3

Нам нужно немного подумать о том, что bind действительно делает за кулисами. В грубом приближении он работает следующим образом:

function bind(fn, ...bound) {
    return (...other) => this.call(fn, ...bound, ...other);
}

(Помните, что лексический this относится к функции, на которой вызывается bind.) Поэтому, беря

apply = bind.bind(bind.apply);

и вручную расширяя bind себя, получаем:

apply = (...other) => bind.call(bind.apply, ...other);

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

apply = (fn) => bind.call(fn.apply, fn);

Но bind (надеюсь) сам также находится на прототипе fn.apply, поэтому мы можем упростить далее:

apply = (fn) => fn.apply.bind(fn);

Теперь мы можем снова расширить bind:

apply = (fn) => (...other) => fn.apply.call(fn, ...other);

На этот раз нам нужны два аргумента, и вызов call также можно упростить:

apply = (fn) => (obj, args) => fn.apply(obj, args);

Теперь мы можем вызывать apply на [].concat:

fn = (obj, args) => [].concat.apply(obj, args);

obj должен быть массивом для работы, поэтому это упрощает:

fn = (obj, args) => obj.concat(...args);

И в приведенном примере мы получаем

[1, 2, 3].concat(4, [5, 6], 7)

который возвращает ожидаемый результат.

Ответ 4

bind() метод создает новый экземпляр функции для значения, которое было передано в bind().

Здесь мы вызываем Function.prototype.bind.apply(Function.prototype, [null].concat(arguments));, разбивая на отдельные исполняемые кодовые единицы.

Цель состоит в вызове apply; передать исходную функцию как первый параметр, а затем массив аргументов.

Эти коды имеют разные переменные для каждого процесса, задействованного для достижения связывания с динамическими параметрами.

var bind=Function.prototype.bind; 
  // the bind function is assigned to a var

var apply=bind.bind(bind.apply); 
  // a new function apply is created which is nothing but bind.apply

var fn=apply([].concat); 
  // the apply function is defined and now we have final function 
   that will concat array.

Последние две строки предназначены для выполнения функции fn путем передачи двух параметров

var a=[1,2,3],b=[4,[5,6],7]; fn(a,b);