Function.prototype.bind - PullRequest
       29

Function.prototype.bind

22 голосов
/ 02 сентября 2011

У меня довольно интересный вопрос о реализации EcmaScript-5 Function.prototype.bind. Обычно, когда вы используете связывание, вы делаете это так:

var myFunction = function() {
    alert(this);
}.bind(123);

// will alert 123
myFunction();

Хорошо, это круто, но что должно произойти, когда мы это сделаем?

// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... 123!
myFunction();

Я понимаю, что это совершенно логичное поведение с точки зрения реализации Function.prototype.bind (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind). Но в реальных условиях это совершенно бесполезное поведение, не так ли? Вопрос в том: это ошибка или функция? Если это ошибка, почему она нигде не упоминается? Если это функция, почему тогда Google Chrome с собственной реализацией "связывания" ведет себя абсолютно так же?

Чтобы было более понятно, что, на мой взгляд, имеет смысл, вот фрагмент кода, который реализует Function.prototype.bind немного по-другому:

if (!Function.prototype.bind) {
    Function.prototype.bind = function() {
        var funcObj = this;
        var original = funcObj;
        var extraArgs = Array.prototype.slice.call(arguments);
        var thisObj = extraArgs.shift();
        var func = function() {
            var thatObj = thisObj;
            return original.apply(thatObj, extraArgs.concat(
                Array.prototype.slice.call(
                    arguments, extraArgs.length
                )
            ));
        };
        func.bind = function() {
            var args = Array.prototype.slice.call(arguments);
            return Function.prototype.bind.apply(funcObj, args);
        }
        return func;
    };
}

Итак, попробуйте это:

// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... "foobar"
myFunction();

На мой взгляд, заменить "это" имеет больше смысла ...

Так что вы, ребята, думаете об этом?

Ответы [ 2 ]

14 голосов
/ 06 сентября 2011

Прецедентом для Function.prototype.bind была реализация идеи в различных JS-средах.Насколько мне известно, ни один из них не позволял изменять связывание this путем последующего связывания.Вы могли бы также спросить, почему никто из них не позволил изменить это связывание, а спросить, почему ES5 не позволяет этого.

Вы не единственный человек, которого я слышал, который считал это странным.Крис Лири, который работает на движке JS Mozilla (как и я), подумал, что это немного странно, подняв эту проблему в Twitter пару месяцев назад.И в несколько ином виде я помню, как один из хакеров Mozilla Labs спрашивал, есть ли какой-нибудь способ «отсоединить» функцию, извлечь из нее целевую функцию.(Если бы вы могли это сделать, вы, конечно, могли бы связать его с другим this, по крайней мере, если бы вы могли также извлечь список связанных аргументов, чтобы также передать его.)

Я не помнювопрос, обсуждаемый при указании bind.Тем не менее, я не обращал особого внимания на список рассылки es-обсуждения во время хэширования.Тем не менее, я не верю, что ES5 слишком много искала для инноваций в этой области, просто «проложите корову», чтобы позаимствовать фразу.

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

2 голосов
/ 25 июля 2013

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

Привязка этой функции в другой раз имеет точно такое же поведение. Если bind каким-то образом вставит в него новое this, то это будет особый случай для уже связанных функций.

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

Я думаю, что ваша путаница заключается в том, что вы рассматриваете bind как изменение существующей функции, и поэтому, если вы измените ее снова, вы ожидаете, что исходная функция будет изменена снова. Однако bind ничего не меняет, он создает новую функцию с определенным поведением. Новая функция сама по себе является функцией, а не магически исправленной версией исходной функции.

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

Только так можно безопасно использовать - если связывание будет иметь значение для уже связанных функций и «нормальных», нужно будет проверить их перед привязкой. Хорошим примером будет jQuery.each, который передает новый this. Если бы связывание было связано со специальными прописными функциями, не было бы безопасного способа передать связанную функцию в jQuery.each, так как это будет перезаписываться при каждом вызове. Чтобы это исправить, jQuery.each должен каким-то образом специализировать связанные функции.

...