Muranx
@Muranx
кто понял this тот в цирке не смеётся

Как понять конструкцию Function.prototype.call.bind(unboundSlice)?

Здравствуйте!

На MDN при описании встроенной в язык функции bind() приводится следующий пример :
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
// . . .
slice(arguments);

Я понимаю что это сокращение конструкции let args = Array.prototype.slice.call(arguments) НО вот хоть убей не понятен момент с bind(), если следовать логике устройства bind() это вспомогательная утилита выглядит примерно так . . .

Function.prototype.bind = function(contextObject){
        let funkToBind = this,
             args = Array.prototype.slice.call(arguments,1)
        return funkToBind.apply( contextObject , args.concat(Array.prototype.slice.call( arguments )))
} // упращение, сущности данной функции

Тоесть метод bind() возвращает новую функцию, которая через замыкание на внешнюю функцию получает контекст, в котором и будет вызываться, т.е.

let b = [1,2];

function ass(){
  return this;
};
console.log((ass.bind(b))()) // [1, 2]

Здесь всё понятно, но я не понимаю случая, когда в call.bind() передаётся функция в качестве контекста (т.е. то, на что будет указывать thisпри вызове call()) :
slice = Function.prototype.call.bind(Array.prototype.slice);

function m(){
    console.log(
       slice(arguments).sort(
        (m,a)=>m-a
       )
    );
};

m(5,3,2,4,1); // [1, 2, 3, 4, 5]

Получается что в данном случа наш вызов утрированно можно переписать следующим образом?
. . .call.bind(Array.prototype.slice){
   return call.apply(Array.prototype.slice)
};

И получается что call() будет вызываться в контексте функции (ну разумеется объекта функции slice(), т.к. в js функции тоже являются объектами)? Хм, ну то, что в результате происходит мне понятно, но вот как работает вызов call() когда контекстом ему передаётся функция мне не очень понятно , т.е. thisпри вызове call() в примере выше будет указывать на [].prototype.slice, в общем быть может кто-нибудь объяснит где мои размышления пошли нетуда, или быть может моё понимание, или я просто что-то путаю, НО я вижу в этой ситуации (сейчас программистам будет сложно, внимание АБСТРАЦИЯ) два пункта, пункт А, в котором два дома, и три жителя (я их всех знаю, и знаю что у них в домах) и вижу пункт Б , который был создан этими тремя жителями из пунтка А, там тоже всё просто, два дома, НО я не пойму как жители пункта А создали это, как они сумели сделать это, и в какой последовательности. . . Извиняюсь за объем текста не нравится не читайте, если видите вопросы больше 6 строк. Пишу так подробно чтобы избежать как минимум 2-ух ответов, и 60ти комментов в духе "чувак, call() вызывает функцию в контексте какого-то объекта, или bind() возвращает новую функцию, или [].prototype.slice нужно чтобы создать новый массив из arguments) и прочая трата времени, плавали , знаем! И если Вы решили написать ответ, попрошу обратить внимание на то, что Я ПОНИМАЮ / НЕ ПОНИМАЮ в этой ситуации , т.к. я довольно подробно постарался описать видение проблемы со своей стороны ! Спасибо за понимание и терпение !
  • Вопрос задан
  • 251 просмотр
Решения вопроса 1
Aetae
@Aetae Куратор тега JavaScript
Тлен
Для call this и должен быть всегда функцией. Это какбэ очевидно из Function.prototype.call: что значит call - встроенный метод любой функции.

Обычно всё непонимание идёт от приписывания this каких-то мистических свойств, в то время как this - простая ссылка, отличающаяся от любой иной переменной только тем, что принимает значение в зависимости от способа вызова и больше ничем.

Ничто не мешает иметь в this функцию:
function foo(num){
  return num
}
function bar(num){
  return this(num);
};
console.log(bar.bind(foo)(99)) // 99


выглядит примерно так . .
Function.prototype.bind = function(contextObject){
        let funkToBind = this,
             args = Array.prototype.slice.call(arguments,1)
        return funkToBind.apply( contextObject , args.concat(Array.prototype.slice.call( arguments )))
} // упращение, сущности данной функции

Не так, а скорее так(но тут не учитывается прототип):
Function.prototype.bind = function(contextObject){
  let funkToBind = this,
      args = Array.prototype.slice.call(arguments,1)
  return function() {
		return funkToBind.apply( contextObject , args.concat(Array.prototype.slice.call( arguments )))
  }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Robur
@Robur
Знаю больше чем это необходимо
Все это затеяно чтобы сократить строку slice.call(arguments);

основное:
тут происходит вызов функции call, в которой в качестве this будет slice.
Соответственно чтобы привязать slice (который будет в this) к call, можно сделать

const boundCall = slice.call.bind(slice);
// теперь можно так:
boundCall(arguments) //то же самое что slice.call(arguments)


дальше уже несущественные вещи в которых вы запутались, slice.call - это Function.prototype.call, можно заменить одно на другое (но не обязательно):
const boundCall = Function.prototype.call.bind(slice);
// теперь можно так:
boundCall(arguments) //то же самое что slice.call(arguments)


Ну и что такое slice - это Array.prototype.slice, получаем:

const slice = Array.prototype.slice
const boundCall = Function.prototype.call.bind(slice);
// теперь можно так:
boundCall(arguments) //то же самое что slice.call(arguments)


теперь переименуем переменные чтоб было как в mdn - slice в unboundSlice, boundCall в slice, получим

const unboundSlice = Array.prototype.slice
const slice = Function.prototype.call.bind(slice);
// теперь можно так:
slice(arguments) //то же самое что slice.call(arguments)


Но все это просто переименование и замена одних букв на другие, что совершенно не меняет логику того происходит, то есть несмотря на громоздкие конструкции, там просто привязывание slice к call в качестве this.

var slice = Array.prototype.slice;
const shortSlice = slice.call.bind(slice);

shortSlice(arguments)// то же самое что и slice.call(arguments)


То что slice в свою очередь тоже функция, как видим, совершенно нигде не проявляется и не имеет значения. тут везде она выступает как объект переданный в this. Остальное - детали реализации call, и это ее дело что она будет с этим объектом делать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы