JavaScript-контекст в анонимных функциях - PullRequest
2 голосов
/ 04 февраля 2011

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

for ( var i = 0; i < object_count; i++ ) {
    objects[i].callback = function(e,x,y){ cb(e,x,y,i) };
}

Однако функция вызывается со значением, которое i имеет в то время.Как бы я сохранил контекст?

Ответы [ 2 ]

10 голосов
/ 04 февраля 2011

Вы можете заключить назначение в функцию или как минимум в правую часть:

    objects[i].callback = (function(i) { return function(e, x, y) {
      cb(e, x, y, i);
    })(i);

«Внешняя» анонимная функция вызывается сразу, копируя переменную цикла «i» в аргумент (который я также назвал «i»; некоторые думают, что делать это непонятно, в то время как другие говорят, что это сбивает с толку не *) 1005 *, чтобы сделать это, так что вы можете решить :-), который затем используется возвращенной «внутренней» анонимной функцией.

Другим подходом к этой проблеме будет использование для этой цели вспомогательной функции вместо простой встроенной анонимной функции. В этом случае это делается немного хитро, потому что вы хотите, чтобы «i» было параметром last фактической функции обратного вызова. Библиотека JavaScript Functional имеет классную утилиту, которая позволяет вам «предварительно заполнить» выбранные аргументы функции фиксированными значениями, предоставляя вам функцию, позволяющую передавать аргументы нефиксированным; это будет выглядеть примерно так:

  objects[i].callback = (function(e, x, y, i) { return cb(e, x, y, i); }).partial(_, _, _, i);

Хорошо это или плохо, это вопрос стиля и мнения.

edit только что выпил немного кофе - я думаю, что я был немного глупым, думая, что мне нужно использовать "partal ()" выше. Тот факт, что внутренняя («настоящая» функция) хочет «i» в конце списка параметров, на самом деле не имеет отношения к тому, как все должно быть настроено. Вышеприведенный пример также можно сделать так:

   objects[i].callback = (function(i, e, x, y) { return cb(e, x, y, i); }).curry(i);

что гораздо менее странно. (Любой из них будет работать, однако. По крайней мере, я думаю, что они будут.: -)

3 голосов
/ 04 февраля 2011

Когда вы пишете

for (var i = something; ...) {
  a[i] = function() { x(i); }
}

Значение i в ваших функциях будет одинаковым для всех функций (это та же переменная, которую вы определяете в области действия вашего цикла for.

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

for (var i = something; ...) {
  (function () {        // using an anonymous function, we create a private context
     var new_i = i;     // new_i has the value of 'i' but exists solely in this
                        // private context
     a[i] = function() { x(new_i); }
                        // the assigned function now refers a variable of the private
                        // context, which will be different on the following loop
                        // iterations
  })();
}

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

...