Что означает `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]
Ответы
Ответ 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);